【问题标题】:React + Redux - Input onChange is very slow when typing in when the input have a value from the stateReact + Redux - 当输入具有来自状态的值时,输入 onChange 非常慢
【发布时间】:2016-01-20 20:30:03
【问题描述】:

我的输入由我所在州的值填充。

<input id="flashVars" name="flashVars" type="text" value={settings.flashVarsValue} disabled={isDisabled} onChange={handleChange} />

Settings是我在 Redux 中的状态。当我在输入中输入一个值时,我必须指定一个 onChange 函数。这是我的 onChange 函数:

handleFlashVarsChange(e) {
  let { dispatch } = this.props;

  dispatch( changeFlashVarsValue(e.target.value) );
}

它将状态值flashVarsValue 更改为输入值。但是当我输入我的输入时,它会滞后。我不明白为什么每次更改输入值时都应该调用调度。

有什么办法可以减少延迟?

我的减速机:

import { ACTIONS } from '../utils/consts';

const initialState = {
  ...
  flashVarsValue: '',
  ...
};

export function formSettings(state = initialState, action = '') {
  switch (action.type) {

    ...

    case ACTIONS.CHANGE_FLASHVARS_VALUE:
      return Object.assign({}, state, {
        flashVarsValue: action.data
      });

    default:
      return state;
  }
}

我的行动:

export function changeFlashVarsValue(data) {
  return {
    type: ACTIONS.CHANGE_FLASHVARS_VALUE,
    data: data
  }
}

谢谢

【问题讨论】:

  • 这个延迟是使用 redux 开发工具还是没有?不先尝试一下,看看是否有帮助。
  • 我还没有使用redux dev-tools,我刚刚开始使用它
  • 你能显示更新你商店的代码吗?我不确定我是否看到了足够的代码来帮助您。
  • 我刚刚更新了关于这个的帖子
  • 看起来不错,我认为这不是滞后的原因。

标签: javascript reactjs redux


【解决方案1】:

我在编辑具有一百万行的网格时遇到了类似的问题,所以我所做的是更改更新逻辑,在您的情况下 handleChange 仅在事件 onBlur 而不是 @987654324 上调用@。这只会在您失去焦点时触发更新。但不知道这是否是您满意的解决方案。

【讨论】:

  • 谢谢你周一试试看;)
  • @MikeBoutin 对你有用吗?我有同样的问题
  • 尝试使用 shouldComponentUpdate 管理更新,它对我有用
  • 不确定我是否是唯一遇到此问题的人,但如果我使用onBlur 而不是onChange,则该字段不会在我输入时更新。
  • 如果您在任何输入中使用onBlur 而不是onChange 并设置属性value,则必须使用defaultValue。这样,它将适用于受控组件。还要记住,每次输入模糊时,都会调用该函数。 Working example
【解决方案2】:

我的答案是使用 shouldComponentUpdate 生命周期钩子。这已经在 Mike Boutin 的评论中给出了答案(大约一年前 :)),但这里的示例可能会对下一位访问者有所帮助。

我遇到了类似的问题,文本输入丢失,速度缓慢且跳跃。我在我的 onChange 事件中使用 setState 来更新 formData。

我发现表单在每次按键时都会重新渲染,因为状态发生了变化。所以为了阻止这种情况,我覆盖了这个函数:

shouldComponentUpdate(nextProps, nextState) {
   return this.state.formErrors !== nextState.formErrors);
}

我在表单提交时显示一个错误通知面板,其中包含任何新的或更改的验证错误,这是我唯一需要重新呈现的时间。

如果您没有子组件,您可能只需将表单组件的 shouldComponentUpdate 设置为始终返回 false。

【讨论】:

  • 来自反应文档“此方法仅作为性能优化存在。不要依赖它来“阻止”渲染,因为这可能会导致错误。” (reactjs.org/docs/react-component.html)
  • 我相信事件处理程序的执行将在 shouldCompomentUpdate 之前按顺序执行,因此这并非在所有情况下都有效。
【解决方案3】:

我知道这是一个老问题,但如果你想在文本输入上触发 onChange,你可能想去抖动你的事件。 This thread 很好地分解了它,但我认为这适用于 op 的示例:

import debounce from 'debounce'                                      

function debounceEventHandler(...args) {
  const debounced = debounce(...args)
  return function (e) {
    e.persist();
    return debounced(e);
  }
}                                                                      
const Container = React.createClass({
  handleFlashVarsChange(e) {
    let { dispatch } = this.props;
    //basic redux stuff
    this.props.changeFlashVarsValue(e.target.value));
  },
  render() {
    const handleChange = debounceEventHandler(this.handleFlashVarsChange, 15);
    return (
      <input id="flashVars" onChange={handleChange} />
    )
  }                                                                         
}
//...prep and return your redux container

【讨论】:

  • 我在想这个 - 但是 - 如果你的 debounce 在 1 秒后设置状态,并且你的输入依赖于状态的变化来更新(重新渲染),你不需要等待 1例如,第二个看到“foo”更改为“bar”?您实际上不会看到单独的“b”、“ba”、“bar”发生变化,对吗?
  • 这仅适用于非受控组件,如果您使用受控组件并且值已去抖动,则输入不会更新。
【解决方案4】:

这里的问题可能是重新渲染。您将“设置”(您的整个状态)传递给包含“输入”的组件,我们不知道您连接的其余组件如何与状态耦合。检查是否由于状态对象的变化,您重新渲染的不仅仅是每次击键时的输入。解决这个问题的方法是更直接地从 mapStateToProps 传递你需要的状态的特定部分(在这种情况下,如果这就是这个组件需要的全部,可能只传递“flashVarsValue”,并确保其他组件也不会全部传递state) 并使用 PureRenderMixin 或 Dan Abramov 的 https://github.com/gaearon/react-pure-render 如果你使用 ES6 组件,如果你的 props 没有改变,则不重新渲染

【讨论】:

    【解决方案5】:

    答案不是在每次击键时都重新渲染组件,只有在用户停止输入时才重新渲染组件。像这样:

    shouldComponentUpdate(nextProps, nextState) {
        if (!textInputReRender)
            return false;
        else
            return true;
    }
    
    onTextInputChange = (propName, propValue) => {
        if (inputChangeTimerId)
            clearTimeout(inputChangeTimerId);
    
        inputChangeTimerId = setTimeout(() => {
            inputChangeTimerId = null;
            const newState = {};
    
            textInputReRender = true;
    
            newState[propName] = propValue;
            this.setState(newState);
        }, 500);
    
        textInputReRender = false;
    }
    

    【讨论】:

      【解决方案6】:

      改用onChangeText

      import { TextInput, View} from "react-native";  
      import { connect } from "react-redux"; 
      import React, { Component, useState } from "react";
      
      function SearchTextInput(props) {
        const { keyword = "", setKeyword } = props; 
        return (
           <TextInput
             style={styles.searchInputText}
             placeholder={"placeholder here"}
             value={keyword}
             onChangeText={setKeyword(t)}
           />
        );
      }
      
      const mapStateToProps = state => {
        return {
          keyword: state.search.keyword,
          search: state.search
        };
      };
      const mapDispatchToProps = dispatch => ({
        setKeyword: payload => dispatch(({type:'updateSearchText', keyword: payload }))
      });
      export default connect(
        mapStateToProps,
        mapDispatchToProps
      )(SearchTextInput);
      

      【讨论】:

      • 这里从来没有谈论过 react-native。
      • @MikeBoutin,它保存了我在 react-native 上的工作:D
      【解决方案7】:

      当您有一个复杂的页面时,这个问题很常见,需要始终重新呈现您更新状态。所以你可以感觉到打字的时候很慢。

      我找到了一个解决方案:组件运行的react生命周期。因此,您可以在调用 onBlur 之后创建其他组件并管理您的事件,例如 onChange,这是由 props 为他传递的。它对我有用:

      import React, {Fragment, useState, useEffect} from 'react';
      import TextField from '@material-ui/core/TextField';
      
      
      export function InputText(props) {
        const [value, setValue] = useState("");
        const {onBlur = (e) => {console.log(e)}, name='name', defaultValue= 'Default', type='text', label='Label'} = props
      
        useEffect(() => {
      
          // console.log(value);
        })
      
        return (
            <label>
              <TextField 
                name={name} 
                label={label}  
                onBlur={e => onBlur(e)}
                type={type}
                value={value}
                onChange={e => setValue(e.target.value)}
              />
            </label>
        );
      }
      
      
      class Sample extends React.Component {
          handleBlurInput = e => {        
               this.setState({ [e.target.name]: e.target.value });
          };
        render() {
          return (
          <InputText name="nome" label="Label Sample" defaultValue={this.state.nome} onBlur={this.handleBlurInput.bind(this)} />
      
          // Complex app ....
          );
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-25
        • 2021-07-02
        • 2020-01-10
        • 2019-10-09
        • 1970-01-01
        • 1970-01-01
        • 2020-01-30
        • 2016-04-25
        相关资源
        最近更新 更多