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

前端 未结 3 1138
情歌与酒
情歌与酒 2020-12-02 12:28

We are creating a large front-end application.

We are using React-Redux for it

We are creating some reusable components.

This question is regarding

相关标签:
3条回答
  • 2020-12-02 12:57

    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

    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

    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

    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.

    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

    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

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

    There is also a Higher-Order Component if you prefer to reduce nesting.

    0 讨论(0)
  • 2020-12-02 12:58

    I interpreted the question to mean:

    • you have content data in the store (e.g. the sections and their titles)
    • you have components for drawing bits of the data (e.g. your <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. E.G. the store state, at one time, may look like this:

    { 
      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. 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:

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

    or

    <SectionHeader title={sections[2].header} />
    
    0 讨论(0)
  • 2020-12-02 13:09

    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. (following FSA) That way you don't need to change your reducer or the mapStateToProps function.

    Also it is compatible with redux-thunk.

    Should be easy to use... reducer-action-interceptor

    0 讨论(0)
提交回复
热议问题