Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/435.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 是否有任何实用的方法可以在组件中调用'React.createContext()'?_Javascript_Reactjs_React Context - Fatal编程技术网

Javascript 是否有任何实用的方法可以在组件中调用'React.createContext()'?

Javascript 是否有任何实用的方法可以在组件中调用'React.createContext()'?,javascript,reactjs,react-context,Javascript,Reactjs,React Context,假设我想为“手风琴”(一组可折叠面板)创建一个UI组件。父组件控制面板打开的状态,而子面板应该能够读取上下文以确定它们是否打开 const Accordion = ({ children }) => { const [openSections, setOpenSections] = useState({}) const isOpen = sectionId => Boolean(openSections[sectionId]) const onToggle = sec

假设我想为“手风琴”(一组可折叠面板)创建一个UI组件。父组件控制面板打开的状态,而子面板应该能够读取上下文以确定它们是否打开

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}
    </>
  )
}
const Accordion=({children})=>{
const[openSections,setOpenSections]=useState({})
常量isOpen=sectionId=>Boolean(openSections[sectionId])
const ontogle=sectionId=>()=>
setOpenSections({…openSections,[sectionId]:!openSections[sectionId]})
const context=usemo(()=>createContext(),[]))
//无法告诉孩子们使用*此*上下文
返回(
({isOpen,ontogle}),[isOpen,ontogle])}>
{儿童}
)
}
const AccordionSection=({sectionId,title,children})=>{
const{isOpen,onToggle}=useContext(上下文)
//无法推断正确的上下文
返回(
{isOpen(sectionId)“'Close':'Open'}
{isOpen&&children}
)
}
我能想到的实现这一点的唯一方法是让
Accordion
children
更改时运行一个效果,然后深入遍历
children
并找到
AccordionSection
组件,同时不递归任何嵌套的
Accordion
组件——然后
cloneElement()
并将
上下文
作为道具注入每个
一致部分

这似乎不仅效率低下,而且我甚至不能完全肯定它会起作用。这取决于
儿童
在效果运行时是否充分水合,我不确定是否会发生这种情况,而且它还要求每当深度儿童发生变化时调用
手风琴
的渲染器,我也不确定这一点


我当前的方法是为实现Accordion的开发人员创建一个自定义钩子。钩子返回一个函数,该函数返回必须手动传递给每个渲染的
一致部分的
isOpen
onToggle
函数。它可以工作,并且可能比子解决方案更优雅,但需要更多的开销,因为开发人员需要使用钩子来维护在
Accordion
中封装的状态。createContext
将返回一个包含两个组件的对象:

  • 提供者
  • 消费者
  • 这两个组件可以共享数据,
    使用者
    可以从树上最近的
    提供者
    中“抓取”上下文数据(或者使用
    使用上下文
    钩子,而不是呈现
    使用者

    您应该在父组件外部创建上下文对象,并使用它在
    子组件内部呈现
    使用者
    (或使用
    使用上下文
    挂钩)

    简单的例子:

    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
      // ...
    }
    
    const myContext=createContext();
    常数手风琴=({children})=>{
    // ...
    返回(
    {儿童}
    )
    }
    const AccordionSection=(…)=>{
    const contextData=useContext(myContext);
    //根据需要使用上下文中的数据
    // ...
    }
    
    请注意,我使用了钩子而不是呈现
    消费者
    ,如果您想使用钩子或
    消费者
    ,则由您决定


    您可以从

    中查看更多示例并获得更多详细信息。不确定为什么要在父级中而不是在父级之外创建上下文。。。(或者为什么要用
    usemo
    )我同意@Sagivb.g。为什么要将其保留在组件中?只需将其移出ISIDE,导出并由其他组件导入即可上下文不仅适用于父对象到子对象,还可以在任何地方使用。只要把它当作一个状态包装器就行了,关键是没有什么是全局唯一的,就像每个手风琴都保持自己的状态,每个部分都是打开的。手风琴的多个实例需要它们自己的上下文。但是React上下文的本质是,当呈现一个“根”组件时,您不能动态地实例化新的上下文实例。我认为这不是在React中可以实际完成的事情。例如,如果您希望应用程序中的Redux存储多于Redux存储,则Redux要求您在从非默认存储读取的每个连接组件上指定存储的名称。因此,我认为需要相同的方法,也就是说,如果一个组件服务于多个上下文,那么子组件需要提供唯一的标识符,而不仅仅是对其最近的提供者父组件的上下文进行神奇的访问。在这里做了一个POC:谢谢你,我错过了一些非常明显的东西!我的印象是,
    createContext()
    创建了一个包含单一上下文值的单一容器。直到现在我才意识到,每个供应商都有自己的价值;因此,多个accordion将使用相同的
    createContext()
    对象,但每个accordion都有自己的上下文数据,只要每个都包装在自己的提供程序中。这是非常有意义的,并且使这成为可能的“正常”方式。谢谢