【问题标题】:Handle Nested Context Providers处理嵌套的上下文提供者
【发布时间】:2020-08-20 13:38:17
【问题描述】:

我的应用中有几个嵌套的上下文提供程序,看起来像这样

export const LangContext = React.createContext("javascript");
export const FontContext = React.createContext("mono-space");
export const FontSizeContext = React.createContext("16px");

const Store = ({ children }) => {
  const [lang, setLang] = useState("javascript");
  const [font, setFont] = useState("mono-space");
  const [fontSize, setFontSize] = useState("16px");
  return (
      <LangContext.Provider value={[lang, setLang]}>
        <FontContext.Provider value={[font, setFont]}>
          <FontSizeContext.Provider value={[fontSize, setFontSize]}>
              {children}
          </FontSizeContext.Provider>
        </FontContext.Provider>
      </LangContext.Provider>
  );
};

我确定这是一种不好的做法,但我不确定如何处理。我希望能够为所有上下文创建一个上下文提供程序。

【问题讨论】:

  • 这不是一个坏习惯。事实上,如果您使用带有状态和调度上下文的减速器,您可能需要进一步分解它们。需要注意的是,如果我们的组件只需要例如字体上下文值,它不应该在 lang-context 更新时重新渲染。所以最好分解上下文。但是,您可能希望对上下文进行逻辑分组。例如,您提到的所有内容似乎都属于单个主题上下文

标签: javascript reactjs react-native react-hooks react-context


【解决方案1】:

您可以简单地使用单个提供程序并将所需的值作为对象传递:

export const StoreContext = React.createContext({});
const Store = ({ children }) => {
  const [lang, setLang] = useState("javascript");
  const [font, setFont] = useState("mono-space");
  const [fontSize, setFontSize] = useState("16px");
  return (
      <StoreContext.Provider value={{lang, setLang, font, setFont, fontSize, setFontSize}}>
              {children}
      </StoreContext.Provider>
  );
};

除了使用useState,您还可以修改上面的内容以使用useReducer 并使API 更加简单:

const initialState= {
   lang: 'javascript',
   font: 'mono-space',
   fontSize: '16px',
}

const reducer = (state, action) => {
    switch (action.type) {
        case 'SET_LANG': return {...state, lang: action.payload}
        case 'SET_FONT': return {...state, font: action.payload}
        case 'SET_FONTSIZE': return {...state, fontSize: action.payload}
        default: return state;
    }
}
export const StoreContext = React.createContext({});
const Store = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
      <StoreContext.Provider value={[state, dispatch]}>
              {children}
      </StoreContext.Provider>
  );
};

在孩子身上你可以像这样使用它:

const Child = () => {
    const [state, dispatch] = useContext(StoreContext);
    const handleChange = (size) => {
         dispatch({type: 'SET_FONTSIZE', payload: size})
    }
    ....
}

【讨论】:

  • 人们使用多个提供商是有原因的!例如只有那些提供者value 已更改的消费者才会重新呈现。使用您当前的语法是所有时间(问题代码具有相同的问题),例如使用useMemo 或像这里这样的单独状态:reactjs.org/docs/context.html#caveats
【解决方案2】:

我想这很好,我也得到了很多Context。但这并不理想,应用程序的结构也很差。

我建议阅读 Kent C. Dodds 的 Application State Management,其中讨论了 Contextprop-drilling 的问题,然后还阅读 points to a Youtube-video,它解释了 组件组成 ,我认为这是一个很好的设计模式,从长远来看可能会导致需要更少的 Context 和更好的管理状态。

我也推荐阅读How to use React Context effectively

【讨论】:

    猜你喜欢
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2019-07-10
    • 2023-03-21
    • 2022-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多