简体   繁体   English

在同一页面/路由上有多个相同的可重用 redux react 组件实例

[英]having multiple instance of same reusable redux react components on the same page/route

We are creating a large front-end application.我们正在创建一个大型前端应用程序。

We are using React-Redux for it我们正在使用 React-Redux

We are creating some reusable components.我们正在创建一些可重用的组件。

This question is regarding having multiple instance of same reusable redux react components on the same page/route这个问题是关于在同一页面/路由上有多个相同可重用 redux react 组件的实例

Problem details:问题详情:

We have a Sectionheader component.我们有一个Sectionheader组件。 Which is bound to redux state.这绑定到 redux 状态。

It listens to the header property reducer SectionheaderReducer .它侦听标题属性 reducer SectionheaderReducer

As we have 2 instances of this Sectionheader on the page both tend to show same values as they are bound to the same store state-property.由于我们在页面上有 2 个此Sectionheader实例, Sectionheader都倾向于显示相同的值,因为它们绑定到相同的商店状态属性。

How to make the redux based reusable react component configurable?如何使基于 redux 的可重用 React 组件可配置? So that each instance can have different value of header property for reducer SectionheaderReducer这样每个实例都可以为 reducer SectionheaderReducer具有不同的 header 属性值

You need to implement some way of namespacing the instances.您需要实现某种命名空间实例的方法。 This can be as basic as passing in a key to differentiate the components and reducers.这可以像传入一个键来区分组件和减速器一样基本。

You can use the ownProps in your mapStateToProps function to guide the mapping to a namespace您可以在mapStateToProps函数中使用ownProps来引导映射到命名空间

const mapStateToProps = (state, ownProps) {
    let myState = state[ownProps.namespace]
    return {
        myState.value
    }
}

The same method can be used to pass on a namespace to the mapDispatchToProps可以使用相同的方法将命名空间传递给mapDispatchToProps

const mapDispatchToProps = (dispatch, ownProps) {
    return {
        myAction: (myParam) => dispatch(myAction(ownProps.namespace, myParam))
    }
}

Just remember to use the namespace in the action type so the reducers don't tread on toes只要记住在动作类型中使用命名空间,这样减速器就不会踩到脚趾

const myAction => (namespace, myParam) {
    return { type: `${namespace}/${MY_TYPE_CONSTANT}`, myParam }
}

And make sure the reducer is namespaced too并确保减速器也有命名空间

const myReducer = (namespace) => (state = initialState, action) => {
    switch(action.type) {
        case `${namespace}/${MY_TYPE_CONSTANT}`:
            return { ...state, action.myParam }
        default:
            return state
    {
}

Now add the 2 namespaced reducers when combining reducers现在在组合减速器时添加 2 个命名空间减速器

combineReducers({
    myInstance1 : myReducer('myInstance1')
    myInstance2 : myReducer('myInstance2')
}

Finally pass the namespace to each instance最后将命名空间传递给每个实例

render() {
    return (
        <div>
            <MyComponent namespace='myInstance1' />
            <MyComponent namespace='myInstance2' />
        </div>
    )
}

Disclaimer: I am the main contributor on the following library.免责声明:我是以下库的主要贡献者。

redux-subspace can provide a more advanced namespacing implementation without you having to reimplement this pattern for every component you want to have multiple instances for. redux-subspace可以提供更高级的命名空间实现,而无需为每个想要拥有多个实例的组件重新实现此模式。

Creating the reducers is similar to above创建减速器与上面类似

const reducer = combineReducers({ 
    myInstance1: namespaced('myInstance1')(myReducer)
    myInstance2: namespaced('myInstance2')(myReducer)
})

Then SubspaceProvider can be used to switch out the state for each component然后可以使用SubspaceProvider来切换每个组件的状态

render() {
    return (
        <div>
            <SubspaceProvider mapState={state => state.myInstance1} namespace='myInstance1'>
                <MyComponent />
            </SubspaceProvider>
            <SubspaceProvider mapState={state => state.myInstance2} namespace='myInstance2'>
                <MyComponent />
            </SubspaceProvider>
        </div>
    )
}

Just ensure you also change your mapStateToProps function to so start traversing from the subtree mapped in the provider只需确保您还将mapStateToProps函数更改为从提供程序中映射的子树开始遍历

const mapStateToProps = (state) {
    return {
        state.value
    }
}

There is also a Higher-Order Component if you prefer to reduce nesting.如果您希望减少嵌套,还有一个高阶组件

I've implemented it in a different way, without actually changing the action name with a namespace.我以不同的方式实现了它,实际上没有使用命名空间更改操作名称。

Rather, I added infra functions which will intercept the action creators and add meta-data to each action.相反,我添加了 infra 函数,它将拦截动作创建者并向每个动作添加meta-data (following FSA ) That way you don't need to change your reducer or the mapStateToProps function. (遵循FSA )这样您就不需要更改减速器或mapStateToProps函数。

Also it is compatible with redux-thunk .它也与redux-thunk兼容。

Should be easy to use... reducer-action-interceptor应该很容易使用... reducer-action-interceptor

I interpreted the question to mean:我将这个问题解释为:

  • you have content data in the store (eg the sections and their titles)您在商店中有内容数据(例如部分及其标题)
  • you have components for drawing bits of the data (eg your <SectionHeader /> )您有用于绘制数据位的组件(例如您的<SectionHeader />
  • you want to display more than one section on a page but currently all your headers have the same text您想在页面上显示多个部分,但目前所有标题都具有相同的文本

One possible solution would have you add the idea of "sections" to your store.一种可能的解决方案是让您将“部分”的想法添加到您的商店。 You'd create reducers that manage the content structure of the data.您将创建管理数据内容结构的 reducer。 EG the store state, at one time, may look like this: EG store 状态有时可能如下所示:

{ 
  sections: {
     0: {
        header: 'My section title',
        content: 'Whatever your content is'
     },
     1: {
        header: 'My other section title',
        content: 'Loads of lovely writing or hrefs to images or whatever'
     }
  }
}

``` ``

You would then have a "container component" or "layout component" or "smart component" (they have many names), that "knows" that you want to use section 2 and section 4 on a particular page.然后,您将拥有一个“容器组件”或“布局组件”或“智能组件”(它们有很多名称),它们“知道”您要在特定页面上使用第 2 部分和第 4 部分。 How it knows this, is up to you.它如何知道这一点,取决于您。 Perhaps you hard-code the indices (because it will always be the same), perhaps you have a filtering rule, perhaps you have another field in the store which defines the choices... etc.也许您对索引进行了硬编码(因为它总是相同的),也许您有一个过滤规则,也许您在商店中有另一个定义选择的字段......等等。

The container component would then pass the chosen heading into the "dumb" , perhaps like this:然后容器组件会将选择的标题传递给 "dumb" ,可能是这样的:

<SectionHeader>{sections[2].header}</SectionHeader>

or或者

<SectionHeader title={sections[2].header} />

将我们的组件转换为哑(无状态)组件,以便这些组件可以轻松重用而不会出现任何复杂情况。

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

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