Javascript 是否有任何实用的方法可以在组件中调用'React.createContext()'?
假设我想为“手风琴”(一组可折叠面板)创建一个UI组件。父组件控制面板打开的状态,而子面板应该能够读取上下文以确定它们是否打开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
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都有自己的上下文数据,只要每个都包装在自己的提供程序中。这是非常有意义的,并且使这成为可能的“正常”方式。谢谢