📜  ReactJS 使用Reducer Hook(1)

📅  最后修改于: 2023-12-03 15:34:41.067000             🧑  作者: Mango

ReactJS 使用Reducer Hook

在React中,我们可以使用Reducer Hook来管理组件的状态,并处理相应的逻辑操作。Reducer Hook是一个函数,接受当前状态和操作类型作为参数,返回新的状态。

使用Reducer Hook

使用Reducer Hook需要进行以下几个步骤:

  1. 定义初始状态 initialState
  2. 定义reducer函数,用于根据操作类型返回新的状态
  3. 使用useReducer Hook,传入初始状态和reducer函数,得到当前状态和dispatch函数
import React, { useReducer } from 'react';

const initialState = {
  count: 0
};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

export default Counter;

在上面的代码中,我们定义了一个初始状态initialState,一个reducer函数reducer,用于根据操作类型返回新的状态,和一个Counter组件,使用了useReducer Hook。

在Counter组件中,我们使用了useReducer Hook,传入我们定义的reducer函数和初始状态。useReducer Hook返回的是当前状态和dispatch函数,我们可以通过dispatch函数来发起针对状态的各种操作。

例如,我们在button的onClick事件处理函数中调用dispatch,以执行increment或decrement操作。当我们点击“+”按钮时,会传入{type: 'increment'}作为参数,这样我们定义的reducer函数就会根据类型返回新的状态,从而更新组件中的计数器。

使用多个Reducer Hook

在一个组件中使用多个Reducer Hook可以更好地组织组件内的状态和逻辑。我们可以定义多个reducer函数,每个reducer函数处理不同的状态和操作类型。

import React, { useReducer } from 'react';

const initialState = {
  count: 0
};

function countReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

const initialNameState = {
  name: 'John Doe'
};

function nameReducer(state, action) {
  switch (action.type) {
    case 'setName':
      return { name: action.payload };
    default:
      throw new Error();
  }
}

function Counter() {
  const [countState, countDispatch] = useReducer(countReducer, initialState);
  const [nameState, nameDispatch] = useReducer(nameReducer, initialNameState);

  return (
    <div>
      <p>Count: {countState.count}</p>
      <button onClick={() => countDispatch({ type: 'increment' })}>+</button>
      <button onClick={() => countDispatch({ type: 'decrement' })}>-</button>

      <p>Name: {nameState.name}</p>
      <input type="text" value={nameState.name} onChange={(e) => nameDispatch({ type: 'setName', payload: e.target.value })} />
    </div>
  );
}

export default Counter;

在上面的代码中,我们定义了两个reducer函数,一个用于处理计数器的状态和操作类型,另一个用于处理姓名的状态和操作类型。

在Counter组件中,我们使用了两个useReducer Hook,分别传入两个reducer函数和相应的初始状态。我们通过countDispatch和nameDispatch来分别发起针对不同状态的操作。

使用Context API和Reducer Hook

在组件树比较深的情况下,我们可能需要在不同层级的组件中共享同一个状态和操作函数,这时我们可以使用Context API和Reducer Hook。

在上面的代码中,我们定义了一个Context,提供了共享的计数器状态和dispatch函数。由于我们的组件状态已经转移到了Provider组件中,所以Counter组件中就不再需要使用useReducer Hook了。而是从Context中获取状态和dispatch函数,执行相关操作。

import React, { useReducer, createContext, useContext } from 'react';

const initialState = {
  count: 0
};

function countReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

const CountContext = createContext();

function Counter() {
  const [state, dispatch] = useReducer(countReducer, initialState);

  return (
    <CountContext.Provider value={{ state, dispatch }}>
      <div>
        <ComponentA />
      </div>
    </CountContext.Provider>
  );
}

function ComponentA() {
  const { state, dispatch } = useContext(CountContext);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>

      <ComponentB />
    </div>
  );
}

function ComponentB() {
  const { state, dispatch } = useContext(CountContext);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

export default Counter;

在上面的代码中,我们定义了一个CountContext,并在Counter组件中使用Provider将共享的状态和操作函数传递给子组件。在ComponentA和ComponentB组件中,我们使用useContext来从CountContext中获取状态和dispatch函数,执行相关操作。

通过使用Context API和Reducer Hook,我们可以更加灵活地管理组件中的状态和操作,让代码更加简洁易懂。