import create from 'xoid'
import React from 'react'
const App = ($props, { effect, read }) => {
const $count = create(0)
const increment = () => $count.update(state => state + 1)
// conditionally callable context reader
const $background = $props.map(({ themeEnabled }) => themeEnabled ? read(ThemeContext) : 'white')
// (also conditionally callable)
effect(() => {
console.log('mount occured')
return () => console.log('unmount occured')
})
// only the following closure rerenders. Outside is static.
// This means there's absolutely no need for `useMemo`, `useCallback`, `useEvent`, even `useRef`.
return (get) => (
<div
style={{ background: get($background) }}
onClick={increment}
>
{get($count)}
</div>
)
}
export default App
High-level summary of the above code:
const App = ($props, { effect, read }) => {
...REMAINS STATIC THROUGHOUT THE COMPONENT LIFECYCLE...
return (get) => {
...RENDER FUNCTION...
}
}
Today, with xoid
, a similar thing is achievable with a few extra steps:
(See: https://xoid.dev/docs/api-react/use-setup)
import { useSetup, useAtom } from '@xoid/react'
const App = (props) => {
const setup = useSetup(($props, { effect, read }) => {
...REMAINS STATIC THROUGHOUT THE COMPONENT LIFECYCLE...
}, props)
return useAtom(() => create((get) => {
...RENDER FUNCTION...
}))
}
In the future I'm planning to add a default export to @xoid/react
package, or create a completely different package that abstracts out the above code to achieve the following. It will have automatic forwardRef capabilities, and resulting components will be wrapped inside React.memo
by default, with a custom equality checker that doesn't check very long strings (Based on my research, this is the only bottleneck of using React.memo ALWAYS).
import component from '@xoid/react'
const App = component(($props, { effect, read, ref* }) => {
...REMAINS STATIC THROUGHOUT THE COMPONENT LIFECYCLE...
return (get) => {
// You can use React hooks here! This means:
// - You can gradually refactor your components if you decide to
// - You can continue using the hooks of third-party React libraries.
...RENDER FUNCTION...
}
})
*: use a proxy, if ref is destructed, wrap it in React.forwardRef
, if not destructed, don't.
Lastly, even useRef
is not need to be imported:
const RefExample = (_, { effect }) => {
const ref = create<HTMLDivElement>()
// do something with ref
effect(() => {
const element = ref.value
...
})
// do something with dynamically changing ref! (no more [ref, setRef] = useState())
ref.subscribe((element) => {
...
})
return () => <div ref={ref.set} />
}