React - Multiple components with the same actions & reducers

前端 未结 1 1617
执笔经年
执笔经年 2021-01-22 02:15

I created a component that lets you add/remove additional dropdowns onClick of a button. I use Redux to keep the state of the added fields and value selected.

It works f

相关标签:
1条回答
  • 2021-01-22 02:19

    I suggest isolating each set of dropdowns as a seperate component, then working on isolating each one's redux state. My library, redux-subspace was designed for this purpose.

    index.jsx

    import React from 'react'
    import { connect } from 'react-redux'
    import { SubspaceProvider } from 'redux-subspace'
    import DropDownField from './form/drop-down-field'
    import uuidV4 from 'uuid-v4'
    import { saveSelect, removeSelect, saveSelectValue } from './actions.js'
    
    
    class Component extends React.Component {
      constructor(props) {
        super(props);
      }
    
      saveData(e) {
        let data = {}
        data[e.target.name] = e.target.value
    
        this.context.store.dispatch(
          addData(data)
        )
      }
    
      addInput = (e) => {
        e.preventDefault()
        this.props.saveSelect({id:uuidV4()})
      }
    
      removeInput = (index, e) => {
        e.preventDefault()
        this.props.removeSelect(index)
      }
    
      saveSelectValue = (e, id) => {
        let data = {}
        data.id = id
        data.value = e.target.value
    
        this.props.saveSelectValue(data)
      }
    
      renderSelections = (selection, index) => {
        const selectedValue = selection.value || ''
        const id = selection.id
    
        return(
          <div>
            <DropDownField
              key={id}
              name={'field-'+ id}
              value={selectedValue}
              onChange = {(e) => { this.saveSelectValue(e, id) }}
              required
              options={this.props.options}  />
    
            <a href="#" onClick={ (e) => {this.removeInput(index, e) }}>Remove</a>
          </div>
        )
      }
    
      render(){
        return (
          <div>
            <DropDownField name={this.props.name} value={this.props.store.value} options={this.props.options} onChange={this.saveData.bind(this)} />
    
            <div>
                {this.props.selections.map(this.renderSelections)}
            </div>
    
            {this.props.selections.length < 4 &&
                <div>
                <a href="#" onClick={this.addInput}>Add</a>
                </div>
            }
          </div>
        )
      }
    }
    
    const mapStateToProps = (state) => {
      return {
        store: state,
        selections: state.selections,
      }
    }
    
    const SingleAddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component)
    
    const AddDropdown = () => {
        return (
            <div>
                <SubspaceProvider mapState={state => state.nationality} namespace="nationalities">
                    <SingleAddDropdown name="Nationality" options={{
                        0: 'Please Select',
                        1: 'British',
                        2: 'French',
                        3: 'American',
                        4: 'Australian'
                    }}/>
                </SubspaceProvider>
                <SubspaceProvider mapState={state => state.countryOfResidence} namespace="countryOfResidence">
                    <SingleAddDropdown name="Country of Residence" options={{ 
                        0: 'Please Select', 
                        1: 'United Kingdom', 
                        2: 'France', 
                        3: 'United States', 
                        4: 'Australia' 
                    }}/>
                </SubspaceProvider>
            </div>
        )
    }
    
    export default AddDropdown
    

    reducer.js

    import ObjectAssign from 'object.assign'
    import { combineReducers } from 'redux'
    import { namespaced } from 'redux-subspace'
    import { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION } from './actions'
    
    function AddDropdown(state = { selections: []}, action = {}){
      switch (action.type){
        case ADD_DATA:
          return ObjectAssign({}, state, action.data)
        case ADD_SELECT:
          return {
            ...state,
            selections: [].concat(state.selections, action.data),
          }
        case REMOVE_SELECT:
          return {
            ...state,
            selections: state.selections.filter((selection, index) => (index !== action.data)),
          }
        case SAVE_SELECT_OPTION:
          return {
            ...state,
            selections: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection)
          }
        default:
          return state
      }
    }
    
    
    const FormApp = combineReducers({
      namespaced(AddDropdown, "nationality"),
      namespaced(AddDropdown, "countryOfResidence")
    })
    
    export default FormApp
    

    NOTE: as per my comment there are some issues with this code and I have not attempted to clean them up for this example.

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