Czy konieczne jest użycie operatora spreadu w użyciu reduktora?
EDYCJA: po sprawdzeniu odpowiedzi Briana dowiedziałem się, że nawet w drugim przykładzie usunięcie ...state
spowodowałoby takie samo zachowanie jak w pierwszym przykładzie, więc to pytanie było błędne. Nie jestem pewien, co spowodowało niewłaściwe zachowanie i przepraszam za wszelkie niedogodności. Odpowiedź Briana jest dobrym wyjaśnieniem zastosowania.
Porównaj następujące 2 fragmenty kodu, robią to samo, aktualizując 2 stany naraz za pomocą initialState
, z wyjątkiem tego, że jeden używa, useState
a drugi używa useReducer
:
useState
const {useState} = React;
const initialState = {
name: 'John',
age: 20
};
const Example = () => {
const [state, setState] = useState(initialState);
const handleName = () => {
setState({...state, name: 'Tom'});
}
const handleAge = () => {
setState({...state, age: 30});
}
return (
<div>
<p>{state.name}</p>
<p>{state.age}</p>
<button onClick={handleName}>
Click to change name
</button>
<button onClick={handleAge}>
Click to change age
</button>
</div>
);
};
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
useReducer
const {useReducer} = React;
const initialState = {
name: 'Tom',
age: 30
}
const reducer = (state, action) => {
switch (action.type) {
case 'name':
return {
...state,
name: 'John'
}
case 'age':
return {
...state,
age: 25
}
default:
return state
}
}
const Example = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Name: {state.name}</p>
<p>Age: {state.age}</p>
<button onClick={() => dispatch({ type: 'name' })}>Click to update name</button>
<button onClick={() => dispatch({ type: 'age' })}>Click to update age</button>
</div>
)
};
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Jeśli usuniesz ...state
w pierwszym przykładzie, ustawia stan na pojedynczą parę klucz / wartość, więc nie działa. Spodziewałem się tego samego w drugim przykładzie, ale tak się nie stało. drugi przykład działa dobrze po usunięciu operatora spreadu.
Mam 3 pytania do drugiego przykładu:
- jaki jest pożytek z operatora spreadu?
- dlaczego nadal działa po usunięciu operatorów rozsiewacza?
- Jeśli działa dobrze bez operatora spreadu, czy to oznacza, że operator spreadu nie jest potrzebny w drugim przykładzie?
Odpowiedzi
Rozumiem, że jest to bardzo podobne pytanie do tego , ale i tak daję odpowiedź, aby miejmy nadzieję, że przyszli czytelnicy nie otrzymają nieprawidłowych informacji.
Ani useState
też useReducer
nie łączy się w ogóle poprzednich wartości. Za zachowanie poprzednich wartości stanu odpowiada użytkownik podczas aktualizacji stanu (w setState
wywołaniu lub w definicji funkcji reduktora).
Możesz to wyraźnie zobaczyć w zmodyfikowanym kodzie poniżej. Wszystko, co zmieniłem, to usunięcie ...state
obudowy z każdego przełącznika.
const {useReducer} = React;
const initialState = {
name: 'Tom',
age: 30
}
const reducer = (state, action) => {
switch (action.type) {
case 'name':
return {
name: 'John'
}
case 'age':
return {
age: 25
}
default:
return state
}
}
const Example = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Name: {state.name}</p>
<p>Age: {state.age}</p>
<button onClick={() => dispatch({ type: 'name' })}>Click to update name</button>
<button onClick={() => dispatch({ type: 'age' })}>Click to update age</button>
</div>
)
};
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Powodem, dla którego operator spreadu jest tak często używany w tym celu, jest najmniej żmudna metoda umieszczania wszystkich niezmienionych wartości w nowym obiekcie.