优化React-Redux连接的PureComponent

时间:2018-04-12 21:34:29

标签: javascript reactjs performance optimization redux

我在尝试优化我的React-Redux应用程序时非常沮丧。

我有一个标题组件,它会在每次更改redux商店时重新加载。我的标题组件是PureComponent

我已经安装了为什么做了更新,它告诉我:

Header.props: Value did not change. Avoidable re-render!

这是我的组件:

export class Header extends PureComponent {

    logout() {
        // this.props.logout();
    }

    signup = () => {
        this.props.history.push(urls.SIGNUP)
    }

    render() {
        console.log("=============== RELOADING HEADER")
        return (
            <div>
                <HeaderContent 
                    logout={this.logout.bind(this)}
                    signup={this.signup.bind(this)}
                    user={this.props.user}/>                    
            </div> 
        )
    }
}

export function mapStateToProps(store) {
    // EDITTED: I initially thought this was causing the problem
    // but i get the same issue when returning a javascript object
    //const u = loginUserFactory(store);
    const u ={}
    return {
        user: u,
    }
}

export function mapDispatchToProps(dispatch) {
    return {
        logout: function l() {
            dispatch(authActions.logout())
        }
    }
}

export function mergeProps(propsFromState,propsFromDispatch,ownProps) {
    return {
        // logout: function logout() {
        //     propsFromDispatch.logout()
        // },
        ...propsFromState,
        ...ownProps
    }
}

let HeaderContainer = connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    {pure: true}
)(Header)

export default withRouter(HeaderContainer);

Header.propTypes = {
    history: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired,
    logout: PropTypes.func.isRequired,
}

我已经验证了每次更改redux存储时都会指示调用render函数的console.log。

如果我取消注释合并道具中的函数,为什么DeanYouUpdate会抱怨该函数导致重新渲染。

重新渲染会严重影响我的应用的效果。我考虑编写自己的shouldComponentUpdate()函数,但是请注意,出于性能原因,在该函数中执行深度等于是一个坏主意。

那我该怎么办?

编辑:

这是Login User Factory中的代码。最初我认为这是问题,但是当我删除该代码时,我仍然会遇到同样的问题。

const loginUserFactory = state => {
    const u = getLoginUser(state);
    const isLoggedIn = !_.isEmpty(u);
    const location = getLocation(state);
    return {
        get id() { return u.id },
        get groupNames() { return u.group_names },
        get avatarSmall() { return u.avatar_small },
        get name() { return u.name },
        get email() { return u.email },

        // my goal was to localize these methods into one file 
        // to avoid repeated code and 
        // to make potential refactoring easier 
        get location() { return location},
        get isHost() {return u.type === "host"},
        get isBooker() {return u.type === "booker"},
        get isLoggedIn() { return isLoggedIn },
    }
}

export default loginUserFactory;

2 个答案:

答案 0 :(得分:4)

我想loginUserFactory()每次调用时都会创建一个新的用户对象,这是每次商店更新时都会因此总是将新的用户对象传递给不等于前一个的组件。

此外,您的Header对用户不做任何事情,除非将其传递到树下。您应该连接HeaderContent组件,并仅将用户对象的属性映射到它实际需要的属性,例如name

一般来说,mapStateToProps()不应该有任何副作用。它应该只在给定状态和自己的道具的情况下过滤/排序/计算连接组件的道具。在最琐碎的情况下,它只会从商店返回属性的子集。

答案 1 :(得分:0)

您在点击处理程序中使用bind。大禁忌!当您在处理程序内部绑定时,每个重新呈现将创建一个全新的函数实例。 bind中的constructor或将您的点击处理程序方法转换为箭头函数。

handleClick = () => {
}

// or

constructor() {
  super()
  this.handleClick = this.handleClick.bind(this)
}

此外,请勿在{{1​​}}或mapStateToProps中实施任何操作或算法。这些也引发了重新渲染。将逻辑放在其他地方。