Skip to content

Instantly share code, notes, and snippets.

@CodyJasonBennett
Last active September 21, 2022 13:20
Show Gist options
  • Save CodyJasonBennett/340427c56a076b1bde6344fa5ce48773 to your computer and use it in GitHub Desktop.
Save CodyJasonBennett/340427c56a076b1bde6344fa5ce48773 to your computer and use it in GitHub Desktop.
R3F cross-container context
import * as React from 'react'
import * as ReactDOM from 'react-dom/client'
import { render } from 'react-nil'
function traverseFiber(fiber, ascending, selector) {
if (selector(fiber) === true) return fiber
let child = ascending ? fiber.return : fiber.child
while (child) {
const match = traverseFiber(child, ascending, selector)
if (match) return match
child = child.sibling
}
}
const contexts = []
function useContextBridge(fiber) {
if (fiber) {
traverseFiber(fiber, true, (node) => {
const context = node.type?._context
if (context && !contexts.includes(context)) contexts.push(context)
})
}
return contexts.reduce(
(Prev, context) => {
const value =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current.readContext(context)
return (props) => (
<Prev>
<context.Provider {...props} value={value} />
</Prev>
)
},
(props) => <React.Fragment {...props} />,
)
}
class FiberProvider extends React.Component {
componentDidMount() {
this.props.setFiber?.(this._reactInternals)
}
render() {
return this.props.children
}
}
const Canvas = React.memo((props) => {
const [fiber, setFiber] = React.useState(null)
const Bridge = useContextBridge(fiber)
render(<Bridge>{props.children}</Bridge>)
return <FiberProvider setFiber={setFiber} />
})
const Context1 = React.createContext(null)
const Context2 = React.createContext(null)
function Providers(props) {
const [value1, setValue1] = React.useState('value1')
const [value2, setValue2] = React.useState('value1')
const [mounted, setMounted] = React.useState(true)
React.useEffect(
() =>
void requestAnimationFrame(() => {
requestAnimationFrame(() => setValue1('value1__new'), setValue2('value2__new'))
requestAnimationFrame(() => requestAnimationFrame(() => setMounted(false)))
}),
[],
)
return (
<Context1.Provider value="invalid">
<Context1.Provider value={value1}>
{mounted ? <Context2.Provider value={value2}>{props.children}</Context2.Provider> : props.children}
</Context1.Provider>
</Context1.Provider>
)
}
function Test() {
console.log(React.useContext(Context1), React.useContext(Context2))
return null
}
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<Providers>
<Canvas>
<Test />
</Canvas>
</Providers>
</React.StrictMode>,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment