Open killjin opened 1 year ago
swapSomponent in router.serPage exec as a promise, then app render before reactive component change.
I see the same behaviour with inertiajs/react:
"name": "@inertiajs/react", "version": "1.0.8",
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'
createInertiaApp({
resolve: async name => {
console.log('Resolve', { name });
return () => <div></div>;
},
setup({ el, App, props }) {
console.log('CreateRoot', { props });
createRoot(el).render(<App {...props} />)
},
})
Resolve is logged twice.
Hey folks! You're right, it's possible for the resolve()
callback to be called more than once — especially during the initial page load.
I'm not sure I see any practical issues with that — other than maybe a perceived performance problem, but that's certainly not something I've ever noticed.
The only other possible problem I could see here is if you're somehow using the resolve()
callback for other things like page visit tracking or something. If that's the case I'd recommend not doing that and instead using the Inertia events instead: https://inertiajs.com/events
I'm not sure that I want to introduce a caching layer here unless completely necessary (although I appreciate your attempt here @craigrileyuk! 🙏).
Is there another reason why this is an issue that I'm not aware of?
I recently faced an issue where the double render caused a flash in the UI, as state in my component differed between first and second renders.
caveat The double render actually pointed out a bug in my code 😳 that I was relying on the second render without noticing, so I should be thanking you instead of reporting an issue. I've fixed it in my own code, so I'm actually ok with the double render now. I'm not sure if it's worth fixing, but figured i'd post the issue I was facing in case it helps someone else, or is important enough to warrant fixing the double render.
The problem arises when you rely on the value of a React ref to make decisions in your component as their state is lagged by 1 render cycle. If you rely on the ref state, the second render can have a different value than the first render since the ref's value is getting hydrated on the first render when being passed a default value.
kinda contrived example:
function SomeComponent({ defaultSearch = '', records } : { defaultSearch: string; records: string[] }){
const searchRef = useRef<HTMLInputElement>(null);
const searchValue = searchRef.current?.value;
function search(e: React.ChangeEvent<HTMLInputElement>) {
// search
}
return (
<div>
<input ref={searchRef} defaultValue={defaultSearch} onChange={search} />
{records.length === 0 &&
(searchValue ? (
<NoResults />
) : (
<EmptyState />
))}
</div>
);
}
In this example above, when defaultSearch
is some truthy string, the UI flashes from the EmptyState to NoResults real quick, because searchValue
is undefined on first render, and then takes the value of defaultSearch
on the second render.
I was able to fix it by updating the value of searchValue
to fallback to defaultSearch
, so not a big deal.
function SomeComponent({ defaultSearch, records } : { defaultSearch: string; records: string[] }){
const searchRef = useRef<HTMLInputElement>(null);
const searchValue = searchRef.current?.value ?? defaultSearch; // fix was adding defaultSearch here
function search(e: React.ChangeEvent<HTMLInputElement>) {
// search
}
return (
<div>
<input ref={searchRef} defaultValue={defaultSearch} onChange={search} />
{records.length === 0 &&
(searchValue ? (
<NoResults />
) : (
<EmptyState />
))}
</div>
);
}
There may be more useful cases for relying on ref being a step behind, and may cause issues for others. Not sure if thats worth pursuing, but figured it was worth mentioning as it took me a bit to figure out why I was seeing a flash.
Same thing happens with fresh "Laravel 11 + Breeze + React" setup (via the Laravel installer). This isn't a vue-specific issue.
Can confirm that this is not vue specific. I got the same double resolve on a Laravel 11 and React App (using Breeze).
I'm fairly new to React (coming from Vue) so I got a bit lost as to why I was getting refresh loop on a live filter index. (I had a useEffect
watching for a data
change, with a get()
)
After looking into React StrictMode, as I thought it was that, the double rendering did help me find a bug and use a ref to track change similarly mentioned by @dbushy727
Version:
@inertiajs/vue3
version: 1.0.8After we've setup our laravel + inertia app we found out that CreateInertiaApp() runs twice.
We tried to find a solution but haven't found one yet.
app.js
webpack.mix.js
I use laravel jetstream, also executed twice. app.js
This results in resolving twice, and if resolve returns a different page the first time than the second, test that each page was resolved.
Why? Can you help us?