teafuljs / teaful

🍵 Tiny, easy and powerful React state management

Home Page:https://npm.im/teaful

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot get new state if in conditional render ( really tricky )

WreewanMorhee opened this issue · comments

teaful: 0.10.0
node: v15.14.0
npm : 7.7.6

import { useEffect, useState } from 'react'
import createStore from 'teaful'
import './App.css'
import ErrorBoundary from './components/ErrorBoundary'

const initialStore = {
	number: 0,
}
export const { useStore } = createStore(initialStore)

function App() {
	const [show, set_show] = useState(false)
	useEffect(() => {
		set_show(true)
	}, [])

	return (
		<ErrorBoundary>
			<div className="App">
				<AA />
				<CC />

				{/* {show && (
					<>
						<AA />
						<CC />
					</>
				)} */}
			</div>
		</ErrorBoundary>
	)
}

const AA = () => {
	const [number] = useStore.number()
	console.warn(number, 45678)

	return number
}

const CC = () => {
	const [number, set_number] = useStore.number()
	if (!number) {
		set_number((prev) => prev + 1)
	}

	return 'c'
}

export default App

works well works fine

BUT
if I put AA and CC into conditional render and other code just stay the same:

import { useEffect, useState } from 'react'
import createStore from 'teaful'
import './App.css'
import ErrorBoundary from './components/ErrorBoundary'

const initialStore = {
	number: 0,
}
export const { useStore } = createStore(initialStore)

function App() {
	const [show, set_show] = useState(false)
	useEffect(() => {
		set_show(true)
	}, [])

	return (
		<ErrorBoundary>
			<div className="App">
				{/* <AA />
				<CC /> */}

				{show && (
					<>
						<AA />
						<CC />
					</>
				)}
			</div>
		</ErrorBoundary>
	)
}

const AA = () => {
	const [number] = useStore.number()
	console.warn(number, 45678)

	return number
}

const CC = () => {
	const [number, set_number] = useStore.number()
	if (!number) {
		set_number((prev) => prev + 1)
	}

	return 'c'
}

export default App

AA cannot get new number anymore
WHY !?

@WreewanMorhee It's nice to find tricky things that they should work properly. Thanks for the error, we will add it as failing test and try to correct it.

I imagine that happens something with the order of instructions, like:

  • CC get number as 0
  • CC subscribes to number property
  • AA get number as 0
  • CC update the property (component AA is not subscribed yet to number)
  • All subscribed components to number property are rerendered.
  • AA subscribes to number property

image

After researching I see that replacing the current store subscription implementation to useSyncExternalStore it should fix this. So we will prioritize changing the subscription system, apart from the fact that it may further reduce the bundle size of the package 😊