React - Multiple Components With The Same Actions & Reducers
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 fine but if
Solution 1:
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
importReactfrom'react'import { connect } from'react-redux'import { SubspaceProvider } from'redux-subspace'importDropDownFieldfrom'./form/drop-down-field'import uuidV4 from'uuid-v4'import { saveSelect, removeSelect, saveSelectValue } from'./actions.js'classComponentextendsReact.Component {
constructor(props) {
super(props);
}
saveData(e) {
let data = {}
data[e.target.name] = e.target.valuethis.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.valuethis.props.saveSelectValue(data)
}
renderSelections = (selection, index) => {
const selectedValue = selection.value || ''const id = selection.idreturn(
<div><DropDownFieldkey={id}name={'field-'+ id}
value={selectedValue}onChange = {(e) => { this.saveSelectValue(e, id) }}
required
options={this.props.options} />
<ahref="#"onClick={ (e) => {this.removeInput(index, e) }}>Remove</a></div>
)
}
render(){
return (
<div><DropDownFieldname={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><ahref="#"onClick={this.addInput}>Add</a></div>
}
</div>
)
}
}
constmapStateToProps = (state) => {
return {
store: state,
selections: state.selections,
}
}
constSingleAddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component)
constAddDropdown = () => {
return (
<div><SubspaceProvidermapState={state => state.nationality} namespace="nationalities">
<SingleAddDropdownname="Nationality"options={{0: 'PleaseSelect',
1: 'British',
2: 'French',
3: 'American',
4: 'Australian'
}}/></SubspaceProvider><SubspaceProvidermapState={state => state.countryOfResidence} namespace="countryOfResidence">
<SingleAddDropdownname="Country of Residence"options={{0: 'PleaseSelect',
1: 'UnitedKingdom',
2: 'France',
3: 'UnitedStates',
4: 'Australia'
}}/></SubspaceProvider></div>
)
}
exportdefaultAddDropdown
reducer.js
importObjectAssignfrom'object.assign'import { combineReducers } from'redux'import { namespaced } from'redux-subspace'import { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION } from'./actions'functionAddDropdown(state = { selections: []}, action = {}){
switch (action.type){
caseADD_DATA:
returnObjectAssign({}, state, action.data)
caseADD_SELECT:
return {
...state,
selections: [].concat(state.selections, action.data),
}
caseREMOVE_SELECT:
return {
...state,
selections: state.selections.filter((selection, index) => (index !== action.data)),
}
caseSAVE_SELECT_OPTION:
return {
...state,
selections: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection)
}
default:
return state
}
}
constFormApp = combineReducers({
namespaced(AddDropdown, "nationality"),
namespaced(AddDropdown, "countryOfResidence")
})
exportdefaultFormApp
NOTE: as per my comment there are some issues with this code and I have not attempted to clean them up for this example.
Post a Comment for "React - Multiple Components With The Same Actions & Reducers"