Reputation: 147
I'm building an online library site and every book has its own page which is set on: /script/:id/ On the book page, I'm showing recommendations for similar books, and when the user clicks one of those, it should redirect him to the book page. Although, when I use useHistory and just push the route there, the URL changes, but the component itself does not rerender with new data.
Route:
<Route exact path="/script/:id">
<ScriptsPage getScript={(e) => getScript(e)} />
</Route>
The component where I'm calling the redirection:
const ScriptCard = ({ title, author, year, image, id }) => {
const [ width, setWidth ] = useState(window.innerWidth);
window.addEventListener('resize', () => setWidth(window.innerWidth));
const history = useHistory();
function redirect() {
history.push(`/script/${id}}`);
}
return (
<div className="scriptcard" onClick={() => redirect()}>
<div className="image">
<img src={`${path}/${image}`} />
</div>
<div className="content">
<h5 className="title">{title}</h5>
<p className="text">{author}</p>
<p className="text">{year}</p>
</div>
</div>
);
};
ScriptsPage
const ScriptsPage = ({ getScript = (f) => f }) => {
const [ , setState ] = useState();
const history = useHistory();
const path = 'http://localhost:8000';
const [ scriptInfo, setScriptInfo ] = useState();
const id = useParams().id;
useEffect(async () => {
const response = await getScript(id);
setScriptInfo(response.data.data);
}, []);
const redirectToViewer = () => {
console.log('redirecting to viewer');
history.push(`/viewer/${id}`);
};
return (
<div>
{!scriptInfo ? (
<h1>Loading</h1>
) : (
<div className="scriptspage">
<div>
// I'm displaying data here, but it has nothing to do
with the question
</div>
<div className="similar-scripts">
<ScriptsCarousel
title={`Viac z kategórie ${scriptInfo.category}`}
id={id}
tag={scriptInfo.category}
limit={10}
/>
</div>
</div>
)}
<Footer />
</div>
);
};
Any ideas on how to solve this?
EDIT: I'm aware that there is an option to use forceRefresh on router itself, but I'd rather solve it on component level rather than having page refreshing in browser on every page redirect.
Upvotes: 0
Views: 1306
Reputation: 366
I think you can use the useEffect(() => {},[])
hook here. However, you must use useState
and use your useHistory()
state in your useEffect
.
useEffect should force a re-render whenever you update your state after pushing:
export default ScriptCard = ({ title, author, year, image, id }) => {
const [width, setWidth] = useState(window.innerWidth);
const [stateHistory, setStateHistory] = useState(useHistory()); // <--- here
const [index, setIndex] = useState(0);
window.addEventListener("resize", () => setWidth(window.innerWidth));
let path = "test";
useEffect(() => {
console.log(`Successfully pushed to ${stateHistory}!`);
}, [stateHistory]); // <--- here
const redir = (stateHistory) => {
stateHistory.push(`/script/${id}`); // <--- here
setStateHistory({ ...stateHistory }); // <--- here
};
return (
<div className="scriptcard" onClick={() => redir(stateHistory)}> // <!-- here -->
<div className="image">
<img alt="test" src={`${path}/${image}`} />
</div>
<div className="content">
<h5 className="title">{title}</h5>
<p className="text">{author}</p>
<p className="text">{year}</p>
</div>
</div>
);
}
You can also add it to ScriptsPage
too.
const ScriptsPage = ({ getScript = (f) => f }) => {
const [ , setState ] = useState();
const [stateHistory, setStateHistory] = useState(useHistory()); // <--- here
const path = 'http://localhost:8000';
const [ scriptInfo, setScriptInfo ] = useState();
const id = useParams().id;
useEffect(async () => {
const response = await getScript(id);
setScriptInfo(response.data.data);
}, []);
useEffect(() => {
console.log(`Successfully pushed to ${stateHistory}!`);
}, [stateHistory]); // <--- here
const redirectToViewer = (stateHistory) => {
console.log('redirecting to viewer');
stateHistory.push(`/viewer/${id}`); // <--- here
setStateHistory({ ...stateHistory }); // <--- here
};
return (
<div>
{!scriptInfo ? (
<h1>Loading</h1>
) : (
<div className="scriptspage">
<div>
// I'm displaying data here, but it has nothing to do
with the question
</div>
<div className="similar-scripts">
<ScriptsCarousel
title={`Viac z kategórie ${scriptInfo.category}`}
id={id}
tag={scriptInfo.category}
limit={10}
/>
</div>
</div>
)}
<Footer />
</div>
);
};
I've also added a codesandbox to help demonstrate.
Upvotes: 1
Reputation: 1409
Add history.go(0)
after your history.push
function redirect() {
history.push(`/script/${id}}`);
history.go(0)
}
Here is a codesandbox with differents usages of react-router, maybe it could help you:
https://codesandbox.io/s/react-router-with-redirect-forked-9jqjh?file=/src/root.js:460-478
Upvotes: 2