将 redux 与 componentWillMount 一起使用时,防止反应组件渲染两次 [英] Prevent react component from rendering twice when using redux with componentWillMount

查看:28
本文介绍了将 redux 与 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆