I am using the following material-ui theme Paperbase and within the Header.js
component, I have the following useEffect
hook:
const [temperature, setTemperature] = useState([]);
const getTemperature= async () => {
try {
const response = await fetch('/get-temperature')
const tempData = await response.json();
setTemperature(tempData);
} catch (err) {
console.error(err.message);
}
};
useEffect(() => {
getTemperature();
}, []);
The main purpose of this, is to display the current temperature as info, within the header component, which gets displayed at first page load/render.
Now within my App.js below, I have the following return
setup where the above Header
component is called.
return (
<Router>
<UserProvider myinfo={myinfo}>
<Switch>
<Route path="/">
<ThemeProvider theme={theme}>
<div className={classes.root}>
<CssBaseline />
<nav className={classes.drawer}>
<Hidden xsDown implementation="css">
<Navigator />
</Hidden>
</nav>
<div className={classes.app}>
<Header
onDrawerToggle={handleDrawerToggle}
/>
<main className={classes.main}>
<Switch>
<Route exact path="/new-user"
render={(props) => <Content key={props.location.key} />}
/>
<Route exact path="/view-results"
render={(props) => <ViewResults key={props.location.key} />}
/>
</Switch>
</main>
</div>
</div>
</ThemeProvider>
</Route>
</Switch>
</UserProvider>
</Router>
);
My question is, how can I trigger a rerender of Header
(parent) whenever the user routes to either /new-user
or /view-results
which in turn calls either Content.js
or ViewResults.js
, inorder to make the useEffect
in Header.js refresh the data, from the REST api fetch and display the latest temperature in the header again?
Ideally anytime Content.js
or ViewResults.js
is rendered, ensure that Header.js getTemperature()
is called.
Any help would be much appreciated.
Your current code is pretty close to a multi layout system. As being a component child of Route
, you can access the current location via useLocation()
or even the native window.location.pathname
.
This is my example of multi layout React app. You can try to use it to adapt to your code.
The MainLayout
use a fallback route when no path
is specified. It also contains a Header
and include a page
const Dispatcher = () => {
const history = useHistory();
history.push('/home');
return null;
};
const App = () => (
<BrowserRouter>
<Switch>
<Route
component={Dispatcher}
exact
path="/"
/>
<Route
exact
path="/login/:path?"
>
<LoginLayout>
<Switch>
<Route
component={LoginPage}
path="/login"
/>
</Switch>
</LoginLayout>
</Route>
<Route>
<MainLayout>
<Switch>
<Route
component={HomePage}
path="/home"
/>
</Switch>
</MainLayout>
</Route>
</Switch>
</BrowserRouter>
);
And here is the code for MainLayout
const MainLayout = ({ children }) => (
<Container
disableGutters
maxWidth={false}
>
<Header location={props.location} />
<Container
component="main"
maxWidth={false}
sx={styles.main}
>
{children}
</Container>
<Footer />
</Container>
);
Now that Header
can be anything. You need to put a capture in this component
import { useLocation } from 'react-router-dom'
cont Header = (props) => {
const { pathname } = useLocation();
//alternatively you can access props.location
useEffect(() => {
if (pathname === '/new-user') {
getTemperature();
}
}, [pathname]);
};
Note that Header is not a direct descendant of Route
therefore it cannot access the location directly via props
. You need to transfer in chain
Route -> MainLayout -> Header
Or better use useLocation