W jakich przypadkach zignorowanie operatora spreadu w useReducer powodowałoby błędy?
W większości useReducer
przykładów, które widziałem, operator rozprzestrzeniania był używany do zachowywania stanów. Jednak we wszystkich moich praktykach ignorowanie tego nigdy nie powodowało żadnych problemów. Wygląda na to, że reduktor jest w stanie sam zachować stan bez operatora rozprzestrzeniania. Sprawdź następujący przykład:
const initialState = {
color: 'black',
bgColor: 'white'
}
const reducer = (state, action) => {
switch (action.type) {
case 'dawn':
return {
...state,
color: 'white',
bgColor: 'purple'
}
case 'reset':
return initialState
default:
return {
state
}
}
}
const UseReducerColorSetter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const { color, bgColor } = state;
return (
<>
<div style={{ color: `${color}`, backgroundColor: `${bgColor}` }} className='card'>
Hello
</div>
<button onClick={() => dispatch({ type: 'dawn' })}>Dawn mode</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</>
)
}
W tym przykładzie usunięcie ...state
nie powoduje żadnych problemów, zmiany stanu, błędu konsoli itp.
W tym pytaniu zadałem: czy konieczne jest użycie operatora spreadu w useReducer , zignorowanie operatora spreadu spowodowało problemy useState
, ale nadal nie ma problemów z useReducer
.
Czy ktoś może mi podać przykłady ignorowania operatora rozprzestrzeniania powodującego problemy useReducer
? Czy reduktor może zachować stan?
Odpowiedzi
Oto działający przykład pokazujący, że jeśli nie zastąpisz wszystkich właściwości obiektu w reduktorze, zostaną one utracone. Porównaj wartości początkowe zarejestrowane w konsoli z wydrukowanym wynikiem.
const initialState = {
color: "black",
bgColor: "white"
};
const reducer = (state, action) => {
switch (action.type) {
case "dawn":
return {
bgColor: "purple" // Updated to only return one property to illustrate the problem
};
case "reset":
return initialState;
default:
return {
state
};
}
};
function App() {
const [state, dispatch] = React.useReducer(reducer, initialState);
React.useEffect(() => {
console.log("Initial: ", state)
dispatch({ type: "dawn" });
}, []);
return <div>{JSON.stringify(state)}</div>;
}
ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>
Zwróć uwagę na podpis funkcji reduktora (state, action) => newState
. Ta funkcja zwraca nowy stan. Więc cokolwiek return
z reduktora jest nową wartością stanu w całości. Oznacza to, że bez rozprzestrzeniania obiektu stanu głównego utracisz wszystkie wartości, które nie zostały jawnie ustawione w nowym obiekcie.
Aby odpowiedzieć bezpośrednio na twoje pytanie, nie rozprzestrzenianie poprzedniego stanu na aktualizacje reduktora spowoduje błędy, gdy stan jest tablicą lub obiektem i nie zastąpisz ręcznie każdej wartości w tej strukturze.
Jeśli zawsze ustawisz każdą właściwość obiektu lub zwrócisz poprzedni stan, nigdy nie napotkasz błędu. To jest scenariusz, który podałeś w pytaniu i dlatego wydaje się niepotrzebny.
W twoim konkretnym przypadku nie wpłynęłoby to ani nie spowodowałoby problemów, ponieważ zmieniasz wartości stanu (kolor i bgColor). może powodować problemy, jeśli aplikacja oczekuje, że będzie zawsze mieć kolor bgColor.
case 'blue':
return {
color: 'blue',
}