So I've scouted for an answer but in most cases its just badly spelling or misplacing the call which I believe its not the case here. It's React logic I somehow find hard to understand.
I'm using This type of React Router and I'm trying to provide Outlet
with a set of data that can be changed while the user is on a children website. I decided to try React Providers instead of React-Router tool useOutletContext because the data provided can grow over time. I decided to follow This approach.
So here is the code. App.jsx
const App = () => {
return (
<AuthProvider>
<Suspense fallback={<Loading />}>
<Routing />
</Suspense>
</AuthProvider>
)
}
Routing.jsx
const BrowserRouter = createBrowserRouter(
createRoutesFromElements(
<Route path="/" name="home" element={<HomePage />}>
<Route path="device" name="device" element={<DevicePage />}>
<Route path=":id" element={<DeviceList />}></Route>
</Route>
<Route path="*" element={<Roadblock.site404 />} />
</Route>,
),
)
export default const Routing = () => {
return <RouterProvider router={BrowserRouter} fallbackElement={<Loading />} />
}
DevicePage.jsx
export default function DevicePage() {
return (
<>
<DeviceContent />
</>
)
}
DeviceContent.jsx
export default function DeviceContent() {
return (
<>
<DeviceProvider>
<Outlet />
</DeviceProvider>
</>
)
}
DeviceProvider.jsx
export const DeviceContext = createContext()
export function DeviceProvider({ children }) {
const [device, setDevice] = useState(null)
const addDevice = () => {
setDevice(data)
}
const deviceContext = {
device,
addDevice,
}
return <DeviceContext.Provider value={deviceContext}>{children}</DeviceContext.Provider>
}
and here is the Outlet
DeviceList.jsx called in Route
export default function DeviceList() {
const { device, addDevice } = useContext(DeviceContext)
addDevice('1')
console.log(device)
return (
<div>
<h2>{device}</h2>
</div>
)
}
Error code
react-dom.development.js:86 Warning: Cannot update a component (
DeviceProvider
) while rendering a different component (DeviceList
). To locate the bad setState() call inside
DeviceList
, follow the stack[...]
Question: What behavior/logic is causing the problem and how can I understand and avoid it in the future?
DeviceList
is enqueueing a state update outside the React component lifecycle. In other words, as an unintentional side-effect. Move the addDevice
call to a useEffect
hook so it's an intentional side-effect.
Example:
import { useEffect } from 'react';
export default function DeviceList() {
const { device, addDevice } = useContext(DeviceContext);
// Update device state when component mounts
useEffect(() => {
addDevice('1');
}, []);
// Log device state updates
useEffect(() => {
console.log(device);
}, [device]);
return (
<div>
<h2>{device}</h2>
</div>
);
};