将react-redux与connect()和{... this.props}一起使用

时间:2016-10-27 15:53:58

标签: reactjs nested redux react-redux

我无法弄清楚,如何做出正确的解决方案,当我想从其他组件调用我的容器中的动作时,我希望使用扩展运算符,因为我需要在我的组件中传递太多参数并且不要# 39;不想描述所有这些。

我知道我可以通过道具从redux商店传递所有道具,比如菜单中的这个例子,但是我的组件太嵌套了,我必须在巢中的eighter组件中发送道具



render() {

        return (
            <div className="wrapper">
                <Menu {...this.props} />
            </div>
        );

    }

}

const mapStateToProps = reduxStore => (
    {
        app: reduxStore.app
    }),

    mapDispatchToProps = dispatch => ({appActions: bindActionCreators(appActions, dispatch)});

export default connect(mapStateToProps, mapDispatchToProps)(App);
&#13;
&#13;
&#13;

所以,我决定将我的嵌套组件与redux store连接起来,因为我需要在我的嵌套组件中使用主容器组件中的store和actions。但是这个解决方案不起作用,因为我使用扩展运算符来嵌套组件。

&#13;
&#13;
render() {

        return <Link activeClassName='active' onClick={this.props.appActions.closeMenu} {...this.props} />;

    }
&#13;
&#13;
&#13;

使用spread运算符非常重要,因为组件从其父组件获取的参数太多,如果我不使用{... this.props},我必须这样写:

&#13;
&#13;
render() {

        const { to, onlyActiveOnIndex, className, specialIcons } = this.props;

        return <Link activeClassName='active' onClick={this.props.appActions.closeMenu} to={to} specialIcons={specialIcons} onlyActiveOnIndex={onlyActiveOnIndex} className={className} >{this.props.children}</Link>;

    }
&#13;
&#13;
&#13;

但是,我必须连接到常见的redux存储,当我连接时,会发生一个错误,因为我的组件使用{... this.props}并且它获得所有道具,包括来自容器和组件的操作。 #39;不知道怎么做。我找到了这个问题的一个解决方案,但我不确定它是正确的变种。我使用扩展运算符克隆道具,但删除包含来自公共存储的新函数(操作)的属性。

&#13;
&#13;
render() {

        let oldProps = {...this.props};
        delete oldProps.appActions;
        delete oldProps.app;

        return <Link activeClassName='active' onClick={this.props.appActions.closeMenu} {...oldProps} >{this.props.children}</Link>;

    }

}

const mapState = reduxStore => ({app: reduxStore.app}),
    mapDispatchToProps = dispatch => ({appActions: bindActionCreators(appActions, dispatch)});

export default connect(mapState, mapDispatchToProps)(NavLink);
&#13;
&#13;
&#13;

我猜我不会理解react-redux中基本和全局的东西,或者我使用不好的做法。可能我应该在React中使用更高阶的组件?但现在我不知道如何做得更好。

1 个答案:

答案 0 :(得分:5)

这是一个功能性的例子。我是为个人项目而做的。为了示例的目的,我删除了无用的代码。 您可能希望获得的东西是eslint,它将向您显示人们在编码时所犯的基本错误。

例如,它会说您已声明了PropTypes。在您的代码中,它在哪里说出应用程序是什么?当然它来自reduxStore.app但它是什么类型的PropTypes?

此外,您不应将所有reduxStore状态链接到您的组件。你应该只输入你真正需要的东西。在我的示例中,我仅从users导入state.app.users。如果我有更多,或想要减速器状态的所有元素,我会单独导入所有这些,然后声明这样的道具:

 Home.propTypes = {
        users: PropTypes.object.isRequired,
        actions: {
            load: PropTypes.func.isRequired,
        },
    };

由于JavaScript不是类型语言,因此上述PropTypes可帮助您进行类型化验证。您还可以看到道具actions,其中包含您在AppActions中导入的所有功能。

要了解如何在之后的操作中使用该功能,请查看我的componentWillMount()

    import React, { Component, PropTypes } from 'react';
    import { ListView} from 'react-native';
    import { connect } from 'react-redux';
    import { bindActionCreators } from 'redux';

    import * as app from '../../actions/appActions';

    const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });

    class Home extends Component {

        constructor(props) {
            super(props);
            this.state = {
                dataSource: ds.cloneWithRows(props.users.toJS()),
            };
        }

        componentWillMount() {
            this.props.actions.load();
        }

        componentWillReceiveProps(nextProps) {
            if (this.props.users !== nextProps.users) {
                this.setState({
                    dataSource: ds.cloneWithRows(nextProps.users),
                });
            }
        }

        render() {
            return (
                  <ListView
                      dataSource={this.state.dataSource}
                      enableEmptySections
                      renderRow={
                          (rowData) => <User haveLunch={rowData.haveLunch} name={rowData.name} />
                      }
                  />
            );
        }
    }

    Home.propTypes = {
        users: PropTypes.object.isRequired,
        actions: {
            load: PropTypes.func.isRequired,
        },
    };

    function mapStateToProps(state) {
        return {
            users: state.app.users,
        };
    }

    function mapDispatchToProps(dispatch) {
        return {
            actions: bindActionCreators(app, dispatch),
        };
    }

export default connect(mapStateToProps, mapDispatchToProps)(Home);

希望这会对你有帮助;)