处理嵌套的上下文提供者

Posted

技术标签:

【中文标题】处理嵌套的上下文提供者【英文标题】: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 更新时重新渲染。所以最好分解上下文。但是,您可能希望对上下文进行逻辑分组。例如,您提到的所有内容似乎都属于单个主题上下文 【参考方案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

【讨论】:

以上是关于处理嵌套的上下文提供者的主要内容,如果未能解决你的问题,请参考以下文章

DCI 上下文中的错误处理?

嵌套中断处理

你可以嵌套 C 预处理器指令吗?

核心数据多线程和嵌套上下文

在 React 上下文中设置嵌套数组

将托管对象上下文附加到嵌套的 UITableViewController