Skip to content

Commit

Permalink
refactor: refactor the initialized logic in Provider
Browse files Browse the repository at this point in the history
  • Loading branch information
awmleer committed Aug 10, 2020
1 parent 58677f9 commit 9f3e8f6
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 14 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "reto",
"version": "0.9.1",
"version": "0.9.2",
"main": "index.js",
"repository": "https://github.com/awmleer/reto",
"description": "React store with hooks.",
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/__snapshots__/store.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ exports[`provider memo 1`] = `
exports[`provider memo 2`] = `
<DocumentFragment>
<p>
3
2
</p>
<p>
3
2
</p>
<p>
1
Expand Down
1 change: 1 addition & 0 deletions src/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export class Container<V> {
constructor(
public state?: V
) {}
initialized = false
notify() {
for (const subscriber of this.subscribers) {
subscriber()
Expand Down
5 changes: 5 additions & 0 deletions src/executor.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import {FC, memo, useEffect} from 'react'
import {Container} from './container'
import {Store, StoreP, StoreV} from './store'

interface Props {
useStore: Store
onChange: (value: StoreV<Store>) => void
container: Container<StoreV<Store>>
args?: StoreP<Store>
memo?: boolean
}

export const Executor: FC<Props> = memo(function Executor(props) {
const args = props.args ?? []
const result = props.useStore(...args)
props.container.state = result
props.container.initialized = true
useEffect(() => {
props.onChange(result)
props.container.notify()
})
return null
}, (prevProps, nextProps) => {
Expand Down
44 changes: 35 additions & 9 deletions src/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import {MutableRefObject, PropsWithChildren, useRef, useState} from 'react'
import {forwardRef, MutableRefObject, PropsWithChildren, useImperativeHandle, useRef, useState} from 'react'
import {Container} from './container'
import {Executor} from './executor'
import {getStoreContext, Store, StoreP, StoreV} from './store'
Expand All @@ -20,21 +20,23 @@ export const Provider = function<S extends Store>(props: PropsWithChildren<Props
}
const container = containerRef.current

const [initialized, setInitialized] = useState(false)
const checkRef = useRef<CheckRef>()
function onChange(value: StoreV<S>) {
if (!initialized) setInitialized(true)
container.state = value
if (props.storeRef) {
props.storeRef.current = value
}
container.notify()
checkRef.current.onInitialize()
}

return (
<Context.Provider value={container}>
<Executor useStore={props.of} args={props.args} onChange={onChange} memo={props.memo}/>
{initialized && props.children}
</Context.Provider>
<>
<Executor useStore={props.of} args={props.args} onChange={onChange} memo={props.memo} container={container}/>
<Context.Provider value={container}>
<Checker container={container} ref={checkRef}>
{props.children}
</Checker>
</Context.Provider>
</>
)
}

Expand All @@ -43,3 +45,27 @@ Provider.displayName = 'Provider'
Provider.defaultProps = {
args: [],
}

interface CheckRef {
onInitialize: () => void
}

const Checker = forwardRef<CheckRef, PropsWithChildren<{
container: Container<any>
}>>((props, ref) => {
const [initialized, setInitialized] = useState(props.container.initialized)

useImperativeHandle(ref, () => ({
onInitialize: () => {
setInitialized(true)
}
}))

return initialized && (
<>
{props.children}
</>
)
})

Checker.displayName = 'Checker'
33 changes: 31 additions & 2 deletions test.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,40 @@
const {useState} = React

function FooStore(initial = 1) {
console.log('rendering FooStore')
const [x, setX] = useState(initial)
console.log('FooStore', x)
return {
x,
setX
}
}

function BarStore() {
console.log('rendering BarStore')
const fooStore = useStore(FooStore)
console.log('BarStore', fooStore.x)
// const [y, setY] = useState(1)

return {
y: fooStore.x + 1,
// setY,
fooStore
}
}

const App = (props) => {
console.log('rendering App')
const fooStore = useStore(FooStore)
// const barStore = useStore(BarStore)

function changeStore() {
fooStore.setX(fooStore.x + 1)
// barStore.setY(barStore.y + 1)
}

// console.log('App', fooStore.x, barStore.y)

return (
<div>
<button onClick={changeStore}>Change</button>
Expand All @@ -38,11 +59,19 @@
)
}

const Child = () => {
console.log('rendering Child')
return <div>
child
</div>
}

ReactDOM.render(
<h1>
Hello, world!
<Provider of={FooStore}>
<App/>
<Provider of={FooStore} memo>
<App/>
<Child/>
</Provider>
</h1>,
document.getElementById('root')
Expand Down

0 comments on commit 9f3e8f6

Please sign in to comment.