将 redux 与 componentWillMount 一起使用时,防止反应组件渲染两次 [英] Prevent react component from rendering twice when using redux with componentWillMount
问题描述
我有一个 React 组件,它在其 componentWillMount
函数中调度 redux 状态更改.原因是组件加载时需要从url中获取id
(由react-router
驱动),并触发一个设置状态的动作使用该 id
的数据.
I have a React component that dispatches a redux state change in its componentWillMount
function. The reason is that when the component is loaded, it needs to get the id
from the url (powered by react-router
), and trigger an action that sets up the state with that id
's data.
这是组件:
class Editor extends React.Component {
componentWillMount() {
const { dispatch, params } = this.props
dispatch(editItem(params.id))
}
render() {
const item = this.props.item
console.log("Editing", item)
}
}
export default connect(state => ({item: state.item}))(Editor)
这里有一个问题:render
被调用了两次.item
在第一次调用时未定义,在第二次调用时有效.理想情况下,它应该只在 this.props.item
实际存在时调用(在 editItem
操作被调度和运行之后).
Here's the catch: render
is getting called twice. item
is undefined on the first call, and valid on the second. Ideally, it should only be called once this.props.item
actually exists (after the editItem
action has been dispatched and run).
根据 React 文档:如果您调用 setState
在此方法中,render()
将看到更新的状态,并且尽管状态发生变化也只会执行一次."
According to the React docs: "If you call setState
within this method, render()
will see the updated state and will be executed only once despite the state change."
在 redux 中,dispatch
相当于调用 setState
,因为它会导致状态改变.但是,我猜测 connect
的工作方式仍然导致 render
被调用两次.
In redux, dispatch
is the equivalent of calling setState
, as it results in a state change. However, I'm guessing something in the way connect
works is still causing render
to be called twice.
除了添加像 if (!item) return;
这样的行之外,还有其他方法吗?
Is there a way around this besides adding a line like if (!item) return;
?
推荐答案
您可能要做的一件事是创建一个高阶组件,在加载所需的 props 之前处理加载不同组件(或不加载组件)的基本模式.
One thing you might do is create a higher order component that handles the basic pattern of loading a different component (or no component) before the required props are loaded.
export const LoaderWrapper = function(hasLoaded, Component, LoaderComponent, onLoad) {
return props => {
if (hasLoaded(props)) {
return <Component {...props} />
}
else {
if (onLoad) onLoad(props)
return { LoaderComponent ? <LoaderComponent /> : null }
}
}
}
然后您可以在连接之前包装您的组件以获得所需的行为.
Then you can wrap your component before connecting it to get the desired behaviour.
export default connect(state => ({item: state.item}))(LoaderWrapper(
((props) => !!props.item),
Editor,
null,
(props) => props.dispatch(editItem(props.params.id))
))
您可能想要添加一些柯里化魔法,以确保您可以更好地组合这些类型的包装函数.查看recompose了解更多信息.
You might want to add some currying magic to make sure you can compose these kinds of wrapper functions more nicely. Take a look at recompose for more info.
这篇关于将 redux 与 componentWillMount 一起使用时,防止反应组件渲染两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!