teaful icon indicating copy to clipboard operation
teaful copied to clipboard

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

Open WreewanMorhee opened this issue 2 years ago • 2 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 avatar Apr 10 '22 09:04 WreewanMorhee

@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

aralroca avatar Apr 10 '22 20:04 aralroca

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 😊

aralroca avatar Apr 11 '22 14:04 aralroca