W jakich przypadkach zignorowanie operatora spreadu w useReducer powodowałoby błędy?

Nov 25 2020

W większości useReducerprzykł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 ...statenie 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

1 BrianThompson Nov 24 2020 at 23:53

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 returnz 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.

SergioVargas Nov 24 2020 at 23:28

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',
            }