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 Apollo 和 Redux:将自定义 reducer 与 Apollo 状态相结合