zl程序教程

您现在的位置是:首页 >  前端

当前栏目

[React] When to useReducer instead of useState

React to of when instead
2023-09-14 09:00:47 时间

useState is typically simpler at first than useReducer (you can even implement useState using useReducer), but there's one scenario where useReducer is almost certainly better than useState:

When one element of your state relies on the value of another element of your state in order to update: useReducer

More information: KcD's blog

 

import React from 'react'
import ReactDOM from 'react-dom'

function undoReducer(state, action) {
  const {past, present, future} = state
  const {type, newPresent} = action

  switch (type) {
    case 'UNDO': {
      if (past.length === 0) return state

      const previous = past[past.length - 1]
      const newPast = past.slice(0, past.length - 1)
      return {
        past: newPast,
        present: previous,
        future: [present, ...future],
      }
    }
    case 'REDO': {
      if (future.length === 0) return state
      const next = future[0]
      const newFuture = future.slice(1)
      return {
        past: [...past, present],
        present: next,
        future: newFuture,
      }
    }
    case 'SET': {
      if (newPresent === present) {
        return state
      }
      return {
        past: [...past, present],
        present: newPresent,
        future: [],
      }
    }
    case 'RESET': {
      return {
        past: [],
        present: newPresent,
        future: [],
      }
    }
    default: {
      throw new Error(`Unhandled action type: ${type}`)
    }
  }
}

function useUndo(initialPresent) {
  const [state, dispatch] = React.useReducer(undoReducer, {
    past: [],
    present: initialPresent,
    future: [],
  })

  const canUndo = state.past.length !== 0
  const canRedo = state.future.length !== 0

  const undo = React.useCallback(() => {
    dispatch({type: 'UNDO'})
  }, [])

  const redo = React.useCallback(() => {
    dispatch({type: 'REDO'})
  }, [])

  const set = React.useCallback(newPresent => {
    dispatch({type: 'SET', newPresent})
  }, [])

  const reset = React.useCallback(newPresent => {
    dispatch({type: 'RESET', newPresent})
  }, [])

  return [state, {set, reset, undo, redo, canUndo, canRedo}]
}

function App() {
  const [state, {set}] = useUndo('first')

  React.useEffect(() => {
    set('second')
  }, [set])

  React.useEffect(() => {
    set('third')
  }, [set])

  return <pre>{JSON.stringify(state, null, 2)}</pre>
}

ReactDOM.render(<App />, document.getElementById('root'))