首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >useReducer状态显然不是无反应状态

useReducer状态显然不是无反应状态
EN

Stack Overflow用户
提问于 2022-01-17 23:52:06
回答 2查看 159关注 0票数 1

我有一个想法,要建立一个反应商店,有点像Vuex。我希望包装器组件接收一个值对象,并使用useContext提供一个对象返回,该对象将stateset附加到对象中的每个键。

例如,如果您将应用程序包装在类似<StoreProvider value={{ color: 'red' }}>的东西中,您可以在任何子const { color } = useContext(StoreContext)中使用它的值和color.state一起使用,然后调用color.set('blue')来全局更改该值。

我用useReducer写了一篇最好的尝试。

代码语言:javascript
复制
import React, {
    createContext,
    useContext,
    useReducer
} from 'react'

const StoreContext = createContext(null)
export const useStoreContext = () => useContext(StoreContext)

export const StoreProvider = ({ children, value }) => {
    
    const reducer = (state, action) => {
        state[action.type].state = action.payload
        return state
    }

    Object.keys(value).map(key => {
        let state = value[key]
        value[key] = {
            state: state,
            set: (setter) => dispatch({ type: key, payload: setter })
        }
    })
 
    const [store, dispatch] = useReducer(reducer, value)

    return (
        <StoreContext.Provider value={store}>
            {children}
        </StoreContext.Provider>
    )
}

还有一个小演示,看看它是否有效:

代码语言:javascript
复制
import React from 'react'
import ReactDOM from 'react-dom'

import { StoreProvider, useStoreContext } from './store'

const App = () => {
  const { color } = useStoreContext()

  return (
    <>
    <h1>{color.state}</h1>
    <button onClick={() => color.set('yellow')}>Change color</button>
    <button onClick={() => console.log(color)}>Log</button>
    </>
  )
}

ReactDOM.render(
  <StoreProvider value={{
    color: 'orange'
  }}>
    <App />
  </StoreProvider>,
  document.getElementById('root')
)

在上面的代码中,<h1>正确地呈现为‘橙色’,但在运行set('yellow')时不会更新为‘黄色’。但是,如果我记录颜色,state已经更新为“黄色”--我猜这意味着状态不是反应性的。

我做了什么蠢事吗?我很有反应能力,以前从未使用过useReducer

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-18 07:29:46

我觉得你错过了一个非常重要的反应点,那就是你永远不应该改变状态对象。state[action.type].state = action.payload是一种状态突变。在突变的基础上,您只需返回相同的状态对象。为了使状态更新正确工作,您必须返回新的对象引用。

代码语言:javascript
复制
const reducer = (state, action) => {
  return {
    ...state,                // <-- shallow copy state
    [action.type]: {
      ...state[action.type], // <-- shallow copy nested state
      state: action.payload,
    }
  };
}

您还误用了array.map回调;您应该真正使用forEach --您正在迭代数组并发出副作用。array.map被认为是一个纯函数。

代码语言:javascript
复制
Object.keys(value).forEach(key => {
  let state = value[key]
  value[key] = {
    state: state,
    set: (setter) => dispatch({ type: key, payload: setter })
  }
});

我无法让您的初始value映射正确工作,似乎是做了一些额外的属性嵌套,这些属性与您在UI中访问或更新的方式不完全匹配。我建议计算初始还原器状态值的方法如下。迭代传递给上下文的value对象的键值对数组,减少为具有相同键的对象,值和setter正确嵌套。

代码语言:javascript
复制
const StoreProvider = ({ children, value }) => {
  const reducer = (state, action) => {
    return {
      ...state,
      [action.type]: {
        ...state[action.type],
        state: action.payload
      }
    };
  };

  const state = Object.entries(value).reduce(
    (state, [key, value]) => ({
      ...state,
      [key]: {
        state: value,
        set: (setter) => dispatch({ type: key, payload: setter })
      }
    }),
    {}
  );

  const [store, dispatch] = useReducer(reducer, state);

  return (
    <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
  );
};

票数 1
EN

Stack Overflow用户

发布于 2022-01-18 00:24:39

我认为,只要要管理的状态没有那么复杂,就可以使用useState钩子简化逻辑:

代码语言:javascript
复制
export const StoreProvider = ({ children, value }) => {
  const { color } = value;

  const [currentColor, setCurrentColor] = useState(color);

  return (
    <StoreContext.Provider value={{ currentColor, setCurrentColor }}>
      {children}
    </StoreContext.Provider>
  );
};

下面是应用程序组件:

代码语言:javascript
复制
const App = () => {
  const { currentColor, setCurrentColor } = useStoreContext();

  return (
    <>
      <h1>{currentColor}</h1>
      <button onClick={() => setCurrentColor('yellow')}>Change color</button>
      <button onClick={() => console.log(currentColor)}>Log</button>
    </>
  );
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70748813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档