简体   繁体   English

有什么实用的方法可以在组件中调用 `React.createContext()` 吗?

[英]Is there any practical way to call `React.createContext()` within a component?

Let's say I want to create a UI component for an "accordion" (a set of collapsible panels).假设我想为“手风琴”(一组可折叠面板)创建一个 UI 组件。 The parent component controls the state of which panels are open, while the child panels should be able to read the context to determine whether or not they're open.父组件控制哪些面板打开的状态,而子面板应该能够读取上下文以确定它们是否打开。

const Accordion = ({ children }) => {
  const [openSections, setOpenSections] = useState({})

  const isOpen = sectionId => Boolean(openSections[sectionId])

  const onToggle = sectionId => () =>
    setOpenSections({ ...openSections, [sectionId]: !openSections[sectionId] })

  const context = useMemo(() => createContext(), [])
    // Can't tell children to use *this* context

  return (
    <context.Provider value={useMemo(() => ({ isOpen, onToggle }), [isOpen, onToggle])}>
      {children}
    </context.Provider>
  )
}

const AccordionSection = ({ sectionId, title, children }) => {
  const { isOpen, onToggle } = useContext(context)
    // No way to infer the right context

  return (
    <>
      <button onClick={onToggle(sectionId)}>{isOpen(sectionId) ? 'Close' : 'Open'}</button>
      {isOpen && children}
    </>
  )
}

The only way I could think of accomplishing this would be to have Accordion run an effect whenever children changes, then traverse children deeply and find AccordionSection components, while not recursing any nested Accordion components -- then cloneElement() and inject context as a prop to each AccordionSection .我能想到的唯一方法是让Accordionchildren发生变化时运行效果,然后深入遍历children并找到AccordionSection组件,同时不递归任何嵌套的Accordion组件——然后cloneElement()并注入context作为道具每个AccordionSection

This seems not only inefficient, but I'm not even entirely sure it will work.这似乎不仅效率低下,而且我什至不完全确定它会起作用。 It depends on children being fully hydrated when the effect runs, which I'm not sure if that happens, and it also requires that Accordion 's renderer gets called whenever deep children change, which I'm not sure of either.这取决于效果运行时children是否完全水合,我不确定是否会发生这种情况,并且它还要求Accordion的渲染器在深度孩子发生变化时被调用,我也不确定。

My current method is to create a custom hook for the developer implementing the Accordion.我目前的方法是为实现手风琴的开发人员创建一个自定义挂钩。 The hook returns a function which returns the isOpen and onToggle functions which have to manually be passed to each rendered AccordionSection .该钩子返回一个函数,该isOpen返回必须手动传递给每个渲染的AccordionSectionisOpenonToggle函数。 It works and is possibly more elegant than the children solution, but requires more overhead as the developer needs to use a hook just to maintain what would otherwise be state encapsulated in Accordion .它有效并且可能比 children 解决方案更优雅,但需要更多的开销,因为开发人员需要使用钩子来维护原本封装在Accordion状态。

React.createContext will return an object that holds 2 components: React.createContext将返回一个包含 2 个组件的对象:

  1. Provider提供者
  2. Consumer消费者

These 2 components can share data, the Consumer can "grab" the context data from the nearest Provider up the tree (or use the useContext hook instead of rendering a Consumer ).这两个组件可以共享数据, Consumer可以从最近的Provider “抓取”树上的上下文数据(或使用useContext钩子而不是呈现Consumer )。

You should create the context object outside the parent component and use it to render a Consumer inside your children components (or use the useContext hook).您应该在父组件外部创建上下文对象,并使用它在children组件内部呈现Consumer (或使用useContext钩子)。

Simple example:简单的例子:

const myContext = createContext();

const Accordion = ({ children }) => {
  // ...
  return (
    <myContext.Provider value={...} >
      {children}
    </myContext.Provider>
  )
}


const AccordionSection = (...) => {
  const contextData = useContext(myContext);
  // use the data of your context as you wish
  // ...
}

Note that i used the useContext hook instead of rendering the Consumer , its up to you if you want to use the hook or the Consumer .请注意,我用的useContext ,而不是渲染钩Consumer ,它取决于你,如果你想使用挂钩,或Consumer

You can see more examples and get more details from the docs您可以查看更多示例并从文档中获取更多详细信息

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

相关问题 默认值的 React.createContext 点? - React.createContext point of defaultValue? 错误:由于对象类型中缺少属性createContext,因此无法调用React.createContext - Error: Cannot call React.createContext because property createContext is missing in object type 使用 React.createContext 将数据从父组件 state 传递到子组件 - passing data from the parent component state to the child component using React.createContext 我无法在 react.createContext() 中访问上下文的功能 - I am not able access functions of a context in react.createContext() React.createContext 如何从单个上下文创建多个实例? - How does React.createContext create multiple instances from a singe context? 有什么办法可以在单击“无反应” dom元素时调用组件方法 - Is there any way to call a component method on clicking a “non react” dom element 在react-leaflet / es / context.js中调用createContext失败 - Call to createContext in react-leaflet/es/context.js fails 骨干调用在React组件函数中不起作用 - Backbone call not working within React component function 还有什么其他方法可以等待来自React组件中Ajax调用的数据 - Is there any other way to wait for data coming from Ajax call in React component 在另一个组件中反应JS调用函数 - React JS call function within another component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM