繁体   English   中英

如何通过 useReducer 和 useContext 在 Custom Hooks 中调度操作?

[英]How to dispatch action in Custom Hooks by useReducer and useContext?

我为按钮切换创建了一个示例。

这是由useContext (存储数据)和useReducer (处理数据)完成的。 它工作正常。

这是CodeSandBox 链接到它是如何工作的。

version 1只是在单击按钮时调度。

然后我创建了一个version 2的切换。 基本上只是将调度放在自定义钩子中。 但不知何故,它不起作用。

// context
export const initialState = { status: false }

export const AppContext = createContext({
  state: initialState,
  dispatch: React.dispatch
})

// reducer
const reducer = (state, action) => {
  switch (action.type) {
    case 'TOGGLE':
      return {
        ...state,
        status: action.payload
      }
    default:
      return state
  }
}

//custom hook
const useDispatch = () => {
  const {state, dispatch} = useContext(AppContext)
  return {
    toggle: dispatch({type: 'UPDATE', payload: !state.status})
    // I tried to do toggle: () => dispatch(...) as well
  }
}

// component to display and interact
const Panel = () => {
  const {state, dispatch} = useContext(AppContext) 
  // use custom hook
  const { toggle } = useDispatch()
  const handleChange1 = () => dispatch({type: 'TOGGLE', payload: !state.status})
  const handleChange2 = toggle // ERROR!!!
  // and I tried handleChange2 = () => toggle, or, handleChange2 = () => toggle(), or handleChange2 = toggle()
  return (
    <div>
      <p>{ state.status ? 'On' : 'Off' }</p>
      <button onClick={handleChange1}>change version 1</button>
      <button onClick={handleChange2}>change version 2</button>
    </div>
  )
}

// root 
export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <AppContext.Provider value={{state, dispatch}}>
      <div className="App">
        <Panel />
      </div>
    </AppContext.Provider>
  );
}

不知道那里发生了什么。 但我认为派出的 state 有问题。

(如果有效载荷没有处理 state,我试过它可以工作,就像一些硬代码的东西,所以此时应该触发调度)

有人可以帮我一把吗? 欣赏!!!

您是正确的,切换需要是 function 但您正在调度操作类型 UPDATE 并且减速器不会对该操作执行任何操作。

丹尼斯是正确的,您提供上下文的初始值没有意义,并且最好将其留空,因为提供者将提供该值。

Dennis 的 useMemo 建议不会优化您的示例,因为 App 在 state 更改时重新渲染,因此永远不会使用记忆值。

这是您的代码的一个工作示例,其中包含我更改的注释:

 const { createContext, useReducer, useContext } = React; const initialState = { status: false }; //no point in setting initial context value const AppContext = createContext(); const reducer = (state, action) => { switch (action.type) { case 'TOGGLE': return {...state, status: action.payload, }; default: return state; } }; const useDispatch = () => { const { state, dispatch } = useContext(AppContext); return { //you were correct here, toggle // has to be a function toggle: () => dispatch({ //you dispatch UPDATE but reducer // is not doing anything with that type: 'TOGGLE', payload: .state,status, }); }; }, const Panel = () => { const { state; dispatch } = useContext(AppContext); const { toggle } = useDispatch(): const handleChange1 = () => dispatch({ type, 'TOGGLE': payload. ;state;status }). const handleChange2 = toggle? // ERROR:;; return ( <div> <p>{state,status, 'On'; 'Off'}</p> <button onClick={handleChange1}> change version 1 </button> <button onClick={handleChange2}> change version 2 </button> </div> ). }, function App() { const [state. dispatch] = useReducer( reducer; initialState ). return ( <AppContext,Provider value={{ state. dispatch }}> <div className="App"> <Panel /> </div> </AppContext;Provider> ); } 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>

好吧,没有React.dispatch这样的东西。 它的值是undefined

export const AppContext = createContext({
  state: initialState,
  // useless
  // dispatch: undefined
  dispatch: React.dispatch
});

// dispatch function won't trigger anything.
const {state, dispatch} = useContext(AppContext);

版本 1实际上应该如何使用上下文,尽管通常,您会想要添加一个额外的记忆步骤(取决于用例),因为在每次渲染时您分配一个新的 object {state,dispatch}总是会导致渲染即使state可能相同。

请参阅此类记忆用例示例。

编辑 black-smoke-6lz6k

如果我的观点不明确,请参阅HMR评论:

应该使用策略性 useMemo,如果许多组件访问上下文,那么当具有提供程序的组件由于更改上下文以外的原因重新呈现时,记忆是一个好主意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM