easy-peasy icon indicating copy to clipboard operation
easy-peasy copied to clipboard

Initial store data is components is always `null`, then loads + re-renders second time to a correct value automatically

Open GavinRay97 opened this issue 5 years ago • 12 comments

This isn't the end of the world, as I can currently wrap every single component and every store value in an if check to see if the data has actually been loaded, but what seems to be happening is that all components mount and render twice -- once with an empty store and then one with the "real" value.

Has anyone seen/heard of this behavior before and have any idea what might be behind it/how to debug? Thank you =)

image

const Table = () => {
	const db = useStoreState(state => state.db)
	const tables = useStoreState(state => state.tables.entries)
	const { name } = useParams()

	console.log("[TABLE COMPONENT]")
	console.log("DB:", db)
	console.log("TABLES:", tables)

	if (!tables || !db) return null

	const table = tables.find(it => it.table_name == name)
	const columns = table?.columns
		.map(it => it.column_name)
		.map(name => ({ Header: name, accessor: name }))

	const req = useQuery(`/table/${name}`, () =>
		db.selectRows(makeRowSelectArgs(table, { limit: 100 }))
	)

	switch (req.status) {
		case "loading":
			return <h1>Loading Tables...</h1>
		case "error":
			return <h1>Error fetching tables: {req.error.message}</h1>
		case "success":
			return <TableComp columns={columns} data={req.data} />
	}
}

Without if (!tables || !db) return null (or equivalent on every component) this happens:

image

GavinRay97 avatar Aug 09 '20 03:08 GavinRay97

Okay it definitely has something do with rehydration and persistence to sessionStorage I'm using.

What I don't understand is why from this logging, the store shows as:

  1. Not rehydrated in <Main> app root
  2. Rehydrated in <Main>, but not rehydrated and empty in <Home>
  3. Still not rehydrated in <Home>, but data is loaded now
  4. Finally decides in <Home> it's rehydrated as well at some point
  5. 3 renders of <Home> happen

If I go by just the rehydration state in <Main> it's still be empty + broken in other components :thinking:

image

const Main = () => {
	const rehydrated = useStoreRehydrated()
	console.log("REHYDRATED?", rehydrated)
	if (!rehydrated) return <p>Loading...</p>
	return (
		<Router>
		  {/* snipped */}
		</Router>
	)
}

const App = () => {
	return (
		<div id="app">
			<StoreProvider store={store}>
				<Main />
			</StoreProvider>
		</div>
	)
}

export default App
const Home = () => {
	const hasura = useStoreState(state => state.hasura)
	const tables = useStoreState(state => state.tables.entries)
	const setTables = useStoreActions(actions => actions.tables.setEntries)
	const rehydrated = useStoreRehydrated()

	console.log("[HOME, index.tsx]")
	console.log("REHYDRATED:", rehydrated)
	console.log("HASURA:", hasura)
	console.log("TABLES:", tables)

	if (!rehydrated) return null

	return (
	  <div class={style.home}>
	    {/* snipped */}
	  </div>
	)
}```

GavinRay97 avatar Aug 09 '20 04:08 GavinRay97

Ignore the above, persist() doesn't seem to have an effect, result is still the same without it =/

GavinRay97 avatar Aug 09 '20 04:08 GavinRay97

@GavinRay97 sorry to hear that you are struggling with this. I have some much improved document improvements for the persist API. My initial thoughts when reading the above was that it was related.

Would you be able to create a small'ish reproducible example for me in CodeSandbox. It would really help me be able to debug this for you.

ctrlplusb avatar Sep 04 '20 08:09 ctrlplusb

@ctrlplusb Hey, appreciate the response!

I found a workaround for this, which might also be useful in providing more info for the problem: If I call useStore().getState() the value is always present/loaded/correct. So it seems to only happen with useStore() passing a selector function. And persistence doesn't impact it at all.

Will try to put up an example repro on Codesandbox this weekend :+1:

GavinRay97 avatar Sep 05 '20 18:09 GavinRay97

We are having a similar issue. When the size of the stored items increased above 5-6mb useStoreRehydrated this hook returns true before the actual rehydrate happens. We put a zero delayed setTimeout to partially fix the problem.

aalpgiray avatar Sep 21 '20 12:09 aalpgiray

I've patched some significant bugs in v4. I have a very strong feeling it will address this issue. There were a few fundamental issues around the persisting and rehydration processes.

ctrlplusb avatar Oct 07 '20 10:10 ctrlplusb

I'll let you know when the patches are released for test.

ctrlplusb avatar Oct 07 '20 10:10 ctrlplusb

Great news! Thanks, mate

aalpgiray avatar Oct 07 '20 11:10 aalpgiray

@aalpgiray would be great to see if the v4 release addresses this issue. 👍

ctrlplusb avatar Oct 15 '20 04:10 ctrlplusb

We are on it. But of course, there are breaking changes. Hope we can do it soon. I'll let you know. Thanks again.

aalpgiray avatar Oct 15 '20 13:10 aalpgiray

No stress. Sorry for any pain. 😅

ctrlplusb avatar Oct 15 '20 13:10 ctrlplusb

I think this might be address in the next alpha:

npm install [email protected]

ctrlplusb avatar Oct 19 '20 07:10 ctrlplusb