简体   繁体   English

Redux:单个容器,多个组件

[英]Redux: Single container, multiple components

I'm quite new to both React and Redux, and I'm unsure about both best practices and technical solution to a case I'm working on.我对 React 和 Redux 都很陌生,我不确定我正在处理的案例的最佳实践和技术解决方案。 I'm using "component" and "container" as defined by Dan Abramov here .我使用的是由丹·阿布拉莫夫定义的“组件”和“容器” 在这里

The component I'm working on is a small collection of filter components: One input text field and two buttons, all filtering a list of entities.我正在处理的组件是一小部分过滤器组件:一个输入文本字段和两个按钮,所有这些都过滤了一个实体列表。 I've tried two approaches:我尝试了两种方法:

First approach: Single component containing three instances of two types of containers, containers connected to corresponding components.第一种方法:单个组件包含两种容器的三个实例,容器连接到相应的组件。

This was what I first made.这是我第一次做的。 Here, the root component looks like the following:在这里,根组件如下所示:

import React, { PropTypes, Component } from 'react';
import Config from '../../config';
import FilterInput from '../containers/FilterInput';
import FilterLink from '../containers/FilterLink'

class FilterController extends Component {
    render() {
        return (
            <div className='filterController'>
                <FilterInput displayName="Search" filterName={Config.filters.WITH_TEXT} />
                <FilterLink displayName="Today" filterName={Config.filters.IS_TODAY} />
                <FilterLink displayName="On TV" filterName={Config.filters.ON_TV} />
            </div>
        )
    }
}
export default FilterController;

The two containers referenced here look pretty much as expected, as do the connected components.这里引用的两个容器和连接的组件看起来很像预期的那样。 I'll show the FilterLink as an example:我将展示 FilterLink 作为示例:

import React, { PropTypes, Component } from 'react';
import {connect} from 'react-redux';
import {toggleFilter} from '../actions';
import FilterButton from '../components/filterbutton'

const mapStateToProps = (state, ownProps) => {
    return {
        active: !!state.program.filters[ownProps.filterName]
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        onClick: () => {
            dispatch(toggleFilter(ownProps.filterName, ownProps.input))
        }
    }
}

const FilterLink = connect(
    mapStateToProps,
    mapDispatchToProps
)(FilterButton)

export default FilterLink

And the corresponding FilterButton component:以及对应的 FilterButton 组件:

import React, { PropTypes, Component } from 'react';

class FilterButton extends Component {

    render() {
        return (
            <button className={this.props.active ? 'active' : ''}
                    onClick={this.props.onClick}>
                {this.props.displayName}
            </button>
        )
    }
}

FilterButton.propTypes = {
    active: PropTypes.bool.isRequired,
    displayName: PropTypes.string.isRequired,
    onClick: PropTypes.func.isRequired,
    filterName: PropTypes.string.isRequired
};

export default FilterButton;

This approach works, but I'm thinking that it shouldn't be necessary to create two different containers.这种方法有效,但我认为没有必要创建两个不同的容器。 Which again lead me to my second attempt.这再次引导我进行第二次尝试。

Second approach: single container containing multiple components.第二种方法:包含多个组件的单个容器。

Here, I made a larger container:在这里,我做了一个更大的容器:

import React, { PropTypes, Component } from 'react';
import Config from '../../config';
import {connect} from 'react-redux';
import {toggleFilter} from '../actions';
import FilterButton from '../components/filterbutton'
import FilterInput from '../components/filterinput'

class FilterContainer extends Component {
    render() {
        const { active, currentInput, onChange, onClick } = this.props;
        return (
            <div className='filterController'>
                <FilterInput displayName="Search" filterName={Config.filters.WITH_TEXT} currentInput={currentInput} onChange={onChange} />
                <FilterButton displayName="Today" filterName={Config.filters.IS_TODAY} active={active} onClick={onClick}/>
                <FilterButton displayName="On TV" filterName={Config.filters.ON_TV} active={active} onClick={onClick}/>
            </div>
        )
    }
}

const mapStateToProps = (state, ownProps) => {
    return {
        active: !!state.program.filters[ownProps.filterName],
        currentInput: state.program.filters[ownProps.filterName] ? state.program.filters[ownProps.filterName].input : ''
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        onClick: () => {
            dispatch(toggleFilter(ownProps.filterName, ownProps.input))
        },
        onChange: newValue => {
            dispatch(toggleFilter(ownProps.filterName, newValue.target.value))
        }
    }
}

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

Here, all state interaction for the entire component is gathered in a single compoment.在这里,整个组件的所有状态交互都集中在一个组件中。 The components are the same here as in the first approach.此处的组件与第一种方法中的组件相同。 This doesn't, however, really work: ownProps is empty in both mapStateToProps and mapDispathToProps.然而,这并没有真正起作用:在 mapStateToProps 和 mapDispathToProps 中 ownProps 都是空的。 I may have misunderstood how the react-redux connection works.我可能误解了 react-redux 连接的工作原理。

So, given these things I have two questions: What's the best way to structure this component, in terms of containers and components?因此,鉴于这些事情,我有两个问题:就容器和组件而言,构建此组件的最佳方法是什么? And secondly, why won't ownProps work similarily in the second approach as in the first?其次,为什么 ownProps 在第二种方法中的工作方式与第一种方法不同?

Thank you for your time.感谢您的时间。

Not sure I have a specific answer regarding structure at the moment.不确定我目前有关于结构的具体答案。 As for "ownProps", that represents props that are specifically being passed in to a given component by its parent.至于“ownProps”,它表示由其父组件专门传递给给定组件的道具。 Since you're connect() -ing FilterController, that means that "ownProps" would be coming from wherever you render that component, like: return <FilterController prop1="a" prop2={someVariable} /> .由于您是connect() -ing FilterController,这意味着“ownProps”将来自您渲染该组件的任何地方,例如: return <FilterController prop1="a" prop2={someVariable} />

Based on how you have those map functions written, it looks like you really want to be connecting the FilterInput and FilterButton components rather than FilterController.根据您编写这些映射函数的方式,看起来您确实想要连接 FilterInput 和 FilterButton 组件而不是 FilterController。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM