React + Redux - 当输入具有来自状态的值时,输入 onChange 非常慢

Posted

技术标签:

【中文标题】React + Redux - 当输入具有来自状态的值时,输入 onChange 非常慢【英文标题】:React + Redux - Input onChange is very slow when typing in when the input have a value from the state 【发布时间】: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,我刚刚开始使用它 你能显示更新你商店的代码吗?我不确定我是否看到了足够的代码来帮助您。 我刚刚更新了关于这个的帖子 看起来不错,我认为这不是滞后的原因。 【参考方案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 ....
    );
  

【讨论】:

以上是关于React + Redux - 当输入具有来自状态的值时,输入 onChange 非常慢的主要内容,如果未能解决你的问题,请参考以下文章

如何在挂钩中比较来自 react redux 状态的值

React/Redux 中具有默认值的文本输入

React Apollo 和 Redux:将自定义 reducer 与 Apollo 状态相结合

试图在 React DOM 上为 CurrentUser 反映来自 CurrentUser 的 Redux 状态变化?

在 Redux 中更新递归对象状态

当 redux 状态更新时,React 组件不更新