I have a ChartPage
function that gets called three times inside three different routers, inside that ChartPage
function I am using "useEffect" that updates some variables according to the chosen route. But for some reason its only triggered once, and when I am going to a different route that using the same ChartPage
function the "useEffect" does not get triggerd again and even when the routes are changing the data is still the same from the first route that got triggered.
Can someone help fix that issue, I tried to solve this for hours
basically I want to trigger "useEffect whenever I click one of the buttons"
app.js:
import React from "react";
import Navbar from "./components/Navbar";
import "./App.css";
import Home from "./components/pages/Home";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import ShowStocks from "./components/pages/ShowStocks";
import ChartPage from "./components/pages/ChartPage";
function App() {
return (
<>
<Router>
<Navbar />
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/show-stocks" element={<ShowStocks />} />
<Route
path="show-stocks/bitcoin"
element={<ChartPage type={"BTC"} />}
/>
<Route
path="show-stocks/ethereum"
element={<ChartPage type={"ETH"} />}
/>
<Route
path="show-stocks/cardano"
element={<ChartPage type={"ADA"} />}
/>
</Routes>
</Router>
</>
);
}
export default App;
as you can see I am using ChartPage
in three different routes but not with the same data
ChartPage.js:
import React, { Component, useState, useEffect } from "react";
import "../../App.css";
import Chart from "../Chart";
import { Button } from "../Button.js";
import "./ChartPage.css";
import axios from "axios";
function getCoin(type) {
console.log("requesting");
var path = `/show-stocks/${type}`;
return axios.get(path).then((response) => {
return response.data;
});
}
export default function ChartPage({ type }) {
const [values, setValues] = useState(null);
// type is changing correctly and the function did get called with a different type
// but useEffect doesn't run on the second time
// so getCoin does not get triggerd and the data stays the same
useEffect(() => {
getCoin(type)
.then((response) => {
setValues(response);
})
.catch((error) => {
console.log(error);
});
}, []);
return (
<>
<div className="chart-page-container">
<h1>{type} Price Market Value</h1>
<div className="chart-container">
{null !== values ? (
<Chart data={[values, type]} />
) : (
<p>Loading...</p>
)}
</div>
<div className="chart-page-btns">
<Button
link="/show-stocks/bitcoin"
className="btns"
buttonStyle="btn--outline2"
buttonSize="btn--large2"
>
Bitcoin
</Button>
<Button
link="/show-stocks/ethereum"
className="btns"
buttonStyle="btn--outline2"
buttonSize="btn--large2"
>
Ethereum
</Button>
<Button
link="/show-stocks/cardano"
className="btns"
buttonStyle="btn--outline2"
buttonSize="btn--large2"
>
Cardano
</Button>
</div>
</div>
</>
);
}
as you can see the buttons changing the routes and type do update according to the parameter that the routes sended, but the useEffect does not called again.
CodePudding user response:
Add type
to the dependencies array of useEffect
:
useEffect(() => {
getCoin(type)
.then((response) => {
setValues(response);
})
.catch((error) => {
console.log(error);
});
}, [type]); // <= HERE
Keep in mind this code has some issues, as you might end up seeing data for a type that doesn't match the one in the URL if something like this happens:
- You navigate to
/type-a
andgetCoin('type-a')
is called. - You navigate to
/type-b
andgetCoin('type-b')
is called. type-b
finishes loading, so itsthen
callback is executed.type-a
finishes loading, so itsthen
callback is executed.- You are now in
/type-b
but see data fromtype-a
.
The proper way to do it would be like this:
useEffect(() => {
let shouldUpdate = true;
getCoin(type)
.then((response) => {
if (shouldUpdate) setValues(response);
})
.catch((error) => {
console.log(error);
});
// This cleanup function will be called if the `useEffect`'s
// dependencies change, so if you run it twice in a row for
// different types, when the result of the first one arrives,
// it will be discarded:
return () => {
shouldUpdate = false;
};
}, [type]);