在我的 react-redux 应用程序中,我有一个受控的文本输入。每次组件更改 value 时,它都会调度一个 action,最后, value 通过 redux 循环返回并被渲染。
在下面的示例中,这运行良好,但在实践中,我遇到了渲染与操作调度异步发生并且输入丢失光标位置的问题。为了演示这个问题,我添加了另一个显式延迟的输入。在单词中间添加一个空格会导致光标在异步输入中跳过。
我对此有两种理论,想知道哪一种是正确的:
哪一个是对的?
工作示例:
http://jsbin.com/doponibisi/edit?html,js,output
const INITIAL_STATE = {
value: ""
};
const reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'SETVALUE':
return Object.assign({}, state, { value: action.payload.value });
default:
return state;
}
};
const View = ({
value,
onValueChange
}) => (
<div>
Sync: <input value={value} onChange={(e) => onValueChange(e.target.value)} /><br/>
Async: <input value={value} onChange={(e) => { const v = e.target.value; setTimeout(() => onValueChange(v), 0)}} />
</div>
);
const mapStateToProps = (state) => {
return {
value: state.value
};
}
const mapDispatchToProps = (dispatch) => {
return {
onValueChange: (value) => {
dispatch({
type: 'SETVALUE',
payload: {
value
}
})
}
};
};
const { connect } = ReactRedux;
const Component = connect(
mapStateToProps,
mapDispatchToProps
)(View);
const { createStore } = Redux;
const store = createStore(reducer);
ReactDOM.render(
<Component store={store} />,
document.getElementById('root')
);
编辑:澄清问题
Marco 和 Nathan 都正确地指出,这是 React 中的一个已知问题,无法修复。如果有
setTimeout
或 onChange
之间的其他延迟并设置该值,光标位置将丢失。但是,setState 只是安排更新这一事实不足以导致此错误发生。在 Github issue Marco 链接,有一条评论:
Loosely speaking, setState is not deferring rendering, it's batching updates and executing them immediately when the current React job has finished, there will be no rendering frame in-between. So in a sense, the operation is synchronous with respect to the current rendering frame. setTimeout schedules it for another rendering frame.
这可以在 JsBin 示例中看到:“同步”版本也使用 setState,但一切正常。
悬而未决的问题仍然是:Redux 内部是否有什么东西会产生延迟,让渲染帧介于两者之间,或者是否可以以一种避免这些延迟的方式使用 Redux?
不需要解决手头问题的解决方法,我找到了一个适用于我的情况的解决方法,但我有兴趣找出更普遍问题的答案。
编辑:问题已解决
我对 Clarks 的回答很满意,甚至还获得了赏金,但当我通过删除所有中间件来真正测试它时,事实证明这是错误的。我还发现了与此相关的 github 问题。
https://github.com/reactjs/react-redux/issues/525
答案是:
最佳答案
您在 Redux 应用程序中使用什么中间件?也许其中一个是在你的 Action 调度周围包装一个 promise 。在没有中间件的情况下使用 Redux 不会表现出这种行为,所以我认为这可能是您的设置所特有的。
关于redux - react 减少 : should the render always happen in the same tick as dispatching an action?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42436068/