使用带有componentWillMount的redux时,防止反应组件呈现两次

时间:2015-12-18 02:09:24

标签: reactjs redux

我有一个React组件,它在componentWillMount函数中调度redux状态更改。原因是当加载组件时,它需要从url获取id(由react-router提供支持),并触发使用id'设置状态的操作数据。

以下是组件:

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操作之后)。

根据React docs:“如果您在此方法中调用setStaterender()将会看到更新后的状态,并且只会在状态发生变化时执行一次。”

在redux中,dispatch相当于调用setState,因为它会导致状态发生变化。但是,我猜测connect的工作方式仍然导致render被调用两次。

除了添加像if (!item) return;

这样的行之外,还有其他方法吗?

3 个答案:

答案 0 :(得分:7)

您可能要做的一件事是创建一个更高阶的组件来处理加载所需道具之前加载不同组件(或没有组件)的基本模式。

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 }
        }
    }
}

然后,您可以在连接组件之前将其包装起来以获得所需的行为。

export default connect(state => ({item: state.item}))(LoaderWrapper(
    ((props) => !!props.item),
    Editor,
    null,
    (props) => props.dispatch(editItem(props.params.id))
))

您可能希望添加一些currying魔法,以确保您可以更好地组合这些类型的包装函数。请查看recompose以获取更多信息。

答案 1 :(得分:2)

看起来反应还原库中已经存在问题。

https://github.com/rackt/react-redux/issues/210

答案 2 :(得分:0)

editItem做什么?它是将项目添加到redux状态还是已经存在?

如果它正在添加我想象发生的事情是当前道具发生渲染周期,即项目为空白。 然后通过设置项目,当道具发生变化时再次渲染。

修复此类事情的一种方法是创建一个更高阶的组件,它包装编辑器并调用调度操作,但是渲染虽然被设置为加载屏幕,但是在设置项目之前设置空div。这样你可以放心,编辑会有一个项目。

但是不知道editItem是什么让它很难知道。也许你可以粘贴代码?