Si quiero enviar una acción cada vez que cambia un estado, actualmente lo hago escuchando ese estado dentro de un componente useEffect hook y enviando una acción cada vez que ese estado cambia.
Por ejemplo, digamos que tengo el siguiente segmento:
export const updateBar = createAsyncThunk("mySlice/updateBar", async () => { const { data } = await axios.get("/some/api"); return data; }); const mySlice = createSlice({ name: "mySlice", initialState: { foo: false, bar: 0, }, reducers: { updateFoo: (state, { payload }) => { state.foo = payload; }, }, extraReducers: { [updateBar.fulfilled]: (state, { payload }) => { state.bar = payload; }, }, }); Ahora, si quiero actualizar la bar cada vez que cambia foo , tengo que ir al lado del componente para agregar el siguiente código:
const Component = () => { const foo = useSelector((state) => state.mySlice.foo); const dispatch = useDispatch(); useEffect(() => { dispatch(updateBar()); }, [dispatch, foo]); return <div></div>; }; Me pregunto si es posible llamar a updateBar cada vez que foo cambie dentro de la porción redux y sin tener que tocar el lado del componente, porque creo que sería más limpio si todos los efectos secundarios del estado se abstrajeran del componente.
Una solución es crear otro procesador que encapsule las dos operaciones de actualización. Realizamos la operación de actualización de foo en este thunk y usamos thunkAPI para enviar la acción de la barra de actualización.
Podemos continuar manteniendo la acción updateFoo cuando solo desea actualizar foo.
Thunk nos ayuda a encapsular la lógica de las acciones. Por ejemplo, cuándo se envían las acciones, qué acciones se envían y su relación, envío en serie o envío concurrente.
P.ej
//@ts-nocheck import { createAsyncThunk, createSlice, configureStore } from '@reduxjs/toolkit'; const mockApi = async () => { return { data: 100 }; }; export const updateBar = createAsyncThunk('mySlice/updateBar', async () => { const { data } = await mockApi(); return data; }); export const updateFooWithBar = createAsyncThunk('mySlice/updateFooWithBar', (arg, thunkAPI) => { // If bar depends on foo state or other state, // you can use thunkAPI.getState() to get the whole state, pick what you need. thunkAPI.dispatch(updateBar()); return arg; }); const mySlice = createSlice({ name: 'mySlice', initialState: { foo: false, bar: 0, }, reducers: { updateFoo: (state, { payload }) => { state.foo = payload; }, }, extraReducers: { [updateBar.fulfilled]: (state, { payload }) => { state.bar = payload; }, [updateFooWithBar.fulfilled]: (state, { payload }) => { state.foo = payload; }, }, }); const store = configureStore({ reducer: mySlice.reducer }); store.subscribe(() => { console.log(store.getState()); }); store.dispatch(updateFooWithBar('next foo')).then(() => { store.dispatch(mySlice.actions.updateFoo('next next foo')); });Resultado de la ejecución:
{ foo: false, bar: 0 } { foo: false, bar: 0 } { foo: 'next foo', bar: 0 } { foo: 'next foo', bar: 100 } { foo: 'next next foo', bar: 100 }