Какой из методов является лучшим для обновления объекта состояния с помощью хука состояния?
Они оба действительны, как указали другие ответы.
в чем разница?
Кажется, что путаница связана с "Unlike the setState method found in class components, useState does not automatically merge update objects"
, особенно с частью "слияния".
Давайте сравним this.setState
& useState
class SetStateApp extends React.Component {
state = {
propA: true,
propB: true
};
toggle = e => {
const { name } = e.target;
this.setState(
prevState => ({
[name]: !prevState[name]
}),
() => console.log(`this.state`, this.state)
);
};
...
}
function HooksApp() {
const INITIAL_STATE = { propA: true, propB: true };
const [myState, setMyState] = React.useState(INITIAL_STATE);
const { propA, propB } = myState;
function toggle(e) {
const { name } = e.target;
setMyState({ [name]: !myState[name] });
}
...
}
Они оба переключают propA/B
в toggle
обработчик.
И они оба обновляют только одну пропущенную пропозицию как e.target.name
.
Обратите внимание на разницу при обновлении только одного свойства в setMyState
.
Следующая демонстрация показывает, что нажатие на propA
вызывает ошибку (которая возникает только setMyState
),
Вы можете следовать по
![Edit nrrjqj30wp](https://codesandbox.io/static/img/play-codesandbox.svg)
Предупреждение: компонент меняет управляемый вход флажка типа, чтобы быть неуправляемым. Входные элементы не должны переключаться с контролируемого на неуправляемый (или наоборот). Выберите между использованием контролируемого или неконтролируемого элемента ввода в течение срока службы компонента.
![error demo](https://i.stack.imgur.com/wGYfE.gif)
Это потому, что когда вы устанавливаете флажок propA
, значение propB
сбрасывается, и переключается только значение propA
, что делает значение propB
checked
неопределенным, что делает флажок неконтролируемым.
И this.setState
обновляет только одно свойство за раз, но оно merges
другое свойство, поэтому флажки остаются под контролем.
Я выкопал исходный код, и поведение вызвано useState
вызовом useReducer
Внутренне, useState
вызывает useReducer
, который возвращает любое состояние, которое возвращает редуктор.
https://github.com/facebook/react/blob/2b93d686e3/packages/react-reconciler/src/ReactFiberHooks.js#L1230
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
...
try {
return updateState(initialState);
} finally {
...
}
},
где updateState
- внутренняя реализация для useReducer
.
function updateState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
return updateReducer(basicStateReducer, (initialState: any));
}
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
Если вы знакомы с Redux, вы обычно возвращаете новый объект, распространяясь по предыдущему состоянию, как вы это делали в варианте 1.
setMyState({
...myState,
propB: false
});
Таким образом, если вы установите только одно свойство, другие свойства не будут объединены.