Reputation: 1
I'm trying to clear fields from a form (clearing state from the store) when the user changes their country so I was wondering if it was possible to dispatch two actions under one event... -- tho my action also doesn't clear the fields so not sure where I'm going wrong
in index.jsx
export default function Form() {
const {
apartmentNumber,
birthDay,
birthMonth,
birthYear,
buildingNumber,
countryCode
} = state;
const [formData, setFormData] = useState({
apartmentNumber,
birthDay,
birthMonth,
birthYear,
buildingNumber
});
const onInputChange = (attribute, value) => {
setFormData({
...formData,
[attribute] : value
});
};
const onCountryChange = (value) => {
dispatch(updateCountry(value));
dispatch(clearForm(formData));
};
in reducer.js --
export const initialState = {
apartmentNumber : '',
birthDay : '',
birthMonth : '',
birthYear : '',
buildingNumber : ''
};
export default (state, action) => {
const { payload, type } = action;
switch (type) {
case UPDATE_COUNTRY:
return {
...state,
countryCode : payload
};
case UPDATE_FIELDS: {
return {
apartmentNumber : initialState.apartmentNumber,
birthDay : initialState.birthDay,
birthMonth : initialState.birthMonth,
birthYear : initialState.birthYear,
buildingNumber : initialState.buildingNumber
};
}
default:
return state;
}
};
Upvotes: 0
Views: 9064
Reputation: 735
You can do this using useReducer React hook. Take note of the createReducer function and how it can be composed to handle arrays of actions.
const createReducer = (actions, state) {
return (state, action) => {
if(Array.isArray(action)) {
actions.forEach(action => {
state = actions[action[i].type](state, action[i])
})
return state
} else if(actions[action.type]) {
return actions[action.type](state, action)
} else {
return state
}
}
}
const actions = {
INCREMENT: (state, action) => {
state.counter++
return state
}
}
const initState = () => ({
counter: 0
})
const reducer = createReducer(actions)
const App = () => {
const [state, setState] = React.useReducer(reducer, initState())
return <div>Count: {state.count}
<button onClick={e => setState([
{type: 'INCREMENT'},
{type: 'INCREMENT'}
])}>+</button>
</div>
}
I suspect your issue is that state is propagating through the DOM tree with every actions dispatched, which can lead to broken or weird DOM states. With this architecture, you apply each of the actions in the array before the state is returned, meaning propagation only occurs after all actions have been applied to the state.
Upvotes: 0
Reputation: 21
You can reset the values be passing in initialState. Ideally, you should have an action for when UPDATE_COUNTRY
is successful. Then you can reset to initialState once the country has been successfully updated.
case UPDATE_COUNTRY_SUCCESS:
return initialState;
or if you don't want to add a success action, you can just do
case UPDATE_COUNTRY:
return {
...initialState,
countryCode: payload
};
Upvotes: 1
Reputation: 1493
As for dispatching multiple actions. You can use redux or if your reducer does not do a side effect you can change your reducer to handle these at one go.
See: Sending multiple actions with useReducers dispatch function?
If your output is not side-effecty you can do similar to: https://codezup.com/how-to-combine-multiple-reducers-in-react-hooks-usereducer/ I don't think you need to use context api for that just pass the reducer and state to the components you want to call dispatch from.
If they have side effects you can achieve chain the effects by setting a reducer which returns the next effect to be ran from useEffect this is useful if you need the ui to change in each disptach. For multiple effects you can combine them and make then all run in one useEffect.
Other than that libs like redux handle these basically out of the box. But I have never used redux.
Upvotes: 0