Как мне получить доступ к предыдущему состоянию внутри функции обратного вызова в реакции? Потому что, когда я обращаюсь к data
, он всегда возвращает исходную версию, так как я использую useEffect
только при монтировании.
const data = useSelector(({ state }) => state.data);
const dispatch = useDispatch();
useEffect(_ => {
dataService.loadData().then(resp => {
dispatch({ type: 'SET_DATA', payload: resp.data });
});
}, []);
const addData = newData => {
dataService.addData(newData).then(_ => {
// need the up to date state here for data
dispatch({ type: 'SET_DATA', payload: [newData, ...data] })
});
}
return <>
<button onClick = {_ => addData({ name: "new name" })}></button>
{data.map(elem => <div>{elem.name}</div>)}
</>
Я думаю, вы неправильно думаете о Redux. Вы получаете доступ к «предыдущему» состоянию в функции редуктора. На самом деле это текущее состояние, но функция редьюсера является функцией состояния и действия, то есть (состояние, действие) => nextState.
Функция редуктора — это место для доступа к состоянию, которое вы пытаетесь обновить.
Пример:
const initialState = {
... other state properties ...
data: [],
};
const reducer = (state = initialState, action) => {
switch(action.type) {
... other cases ...
case SET_DATA:
return {
...state,
data: [action.payload, ...data],
}
default:
return state;
}
};
Затем обработчик addData
просто отправляет действие с newData
в полезной нагрузке.
const addData = newData => {
dataService.addData(newData)
.then(_ => {
dispatch({ type: 'SET_DATA', payload: newData })
});
};
Если вам нужно различать загрузка для данных и добавление для них в отношении того, как они обрабатываются и обновляют состояние, я предлагаю использовать отдельные типы действий, например SET_DATA
и ADD_DATA
.
Что, если мне нужно проверить, содержит ли data
некоторые элементы перед обновлением состояния?
Означает ли это, что хуки реакции поддерживают доступ к состоянию только внутри функции dispatch
?
@LabLab Возвращает ли всегда исходное значение data
или это просто обновление? Из кода, которым вы поделились, не совсем понятно, почему вы можете видеть какие-либо устаревшие вложения поверх data
. Если вам нужно проверить, содержит ли data
некоторые элементы перед обновлением состояния, вы можете сделать это в редьюсере, где у вас есть как текущее состояние и, так и полезная нагрузка действия. Я не совсем понимаю ваш последний вопрос, но я склонен сказать нет, есть несколько способов получить доступ к состоянию редукции.
Итак, покопавшись в stackoverflow и прочитав множество статей о реакции, я обнаружил, что невозможно получить доступ к актуальному значению состояния в функции обратного вызова, когда useEffect
вызывается только один раз при монтировании.
Хотя это не проблема, если вы используете компонент класса.
Для функциональные компоненты вам нужно использовать функцию dispatch
, у которой есть доступ к текущему состоянию. Итак, чтобы правильно обновить мои данные, я использовал следующий код:
const addData = newData => {
dispatch(addDataDispatch(newData));
}
В вашем редукторе:
export const addDataDispatch = newData => {
return (dispatch, getState) => {
const {state: {data}} = getState();
if (data.includes(newData)) return;
dataService.addData(newData).then(_ => {
dispatch({ type: 'SET_DATA', payload: [newData, ...data] })
});
}
}
Я полностью с вами согласен, но все же мне интересно, почему
data
внутри функции обратного вызова всегда равно тому, что в начальном состоянии? Почему это значение не содержит значение актуального состояния?