I'm following this design pattern from React-admin to define the parent Team resource,
but the useEffect hook is being called 4 times on every page refresh
The context provider is just to be able to pass the Teams list to a select in the layout, if I remove it, the same problem happens
Is this expected behaviour?
const AdminEnterprise = () => {
return (
<AdminContext
disableTelemetry
authProvider={authProvider}
dataProvider={dataProvider}
>
<TeamResources />
</AdminContext>
);
};
const TeamResources = () => {
const dataProvider = useDataProvider();
const [state, dispatch] = useReducer(teamReducer, {
loading : true,
teams : []
})
useEffect(() => {
//This is called 4 times on page refresh
console.log('querying user teams')
dataProvider.getList('userTeams')
.then(({data}) =>{
dispatch({
teams: data,
selected: data[0].id,
loading: false
})
})
.catch(error => {
dispatch({
error: error,
loading: false
})
})
}, [])
return (
<TeamContext.Provider value={[state, dispatch]}>
{state.loading? <></> : (
<AdminUI layout={MyLayout} loginPage={CustomLoginPage} theme={myTheme}>
<Resource name={`teams/${state.selected}/projects`} list={ProjectList} options={{label: 'Projects' }}/>
<Resource name={`teams/${state.selected}`} />
</AdminUI>
)}
</TeamContext.Provider>
)
}
Obviously, you have root re-rendering from the AdminEnterprise component, your TeamResources is correct, but you can optimize it from top-level or optimize it by using React.memo inside the TeamResources component (recommended). You can export it by memo:
const TeamResources = () => {
~ ~ ~
};
export default React.memo(TeamResources);
For tuning the React.memo you can have more information here
The "expected" behaviour is for anything inside useEffect() with an empty dependency array ([] as the second argument) to only run once.
The AdminContext tree is likely re-rendering based on changes to dataProvider or some other side-effects of invoking dataProvider.getList(). We can't see that, so it's tough to help.
Here's at least a suggested method to verify that the problem isn't inside TeamResources:
# in Test.jsx
const Test = () => {
console.log('Test is rendering.');
useEffect(() => {
console.log('Test, inside useEffect');
}, []);
return <></>;
};
# in AdminContext.jsx
<AdminContext
disableTelemetry
authProvider={authProvider}
dataProvider={dataProvider}
>
<Test />
<TeamResources />
</AdminContext>
I'd suspect that 'Test, inside useEffect' is going to be logged more often than expected too.
I think your authProvider or dataProvider change asynchronously. Therefore AdminContext component re-renders is again. So check it in the AdminEnterprise component.
const AdminEnterprise = () => {
if (!authProvider || !dataProvider) return null;
return (
<AdminContext
disableTelemetry
authProvider={authProvider}
dataProvider={dataProvider}
>
<TeamResources />
</AdminContext>
);
};