首页 文章

优化React-Redux连接的PureComponent

提问于
浏览
0

我试图优化我的React-Redux应用程序时非常令人沮丧 .

我有一个 Headers 组件,在每次更改redux商店时重新加载 . 我的 Headers 组件是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 回答

  • 4

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

    handleClick = () => {
    }
    
    // or
    
    constructor() {
      super()
      this.handleClick = this.handleClick.bind(this)
    }
    

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

  • 0

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

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

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

相关问题