Issue
I'm using Ionic 7 and React 18. I would like to activate a different component in my container if the hash portion of the URL changes. I have tried doing this:
const MyContainer: React.FC<ContainerProps> = () => {
...
useEffect(() => {
// Set step based on the hash in the URL
const hash = window.location.hash.substring(1); // Remove the '#' from the hash
switch (hash) {
...
case 'message':
dispatch(setStep(StepsEnum.Message));
break;
}
}, []);
...
{step === StepsEnum.Name && <MyFirstComponent />}
{step === StepsEnum.Address && <MySecondComponent />}
{step === StepsEnum.Message && <MyThirdComponent />}
</IonContent>
</IonPage>
)
}
export default MyContainer
Unfortunately, when I type in a different hash in my browser, nothing happens (at least, I don't see my useEffect getting called). Is it possible to activate a different component based on the URL's hash?
Solution
Unless you use a router, such as React Router, that provides hook that track URL changes, you'll need to explicitly listen to the hashchange
event.
Example (click the links):
const { useState, useEffect } = React;
const MyContainer = () => {
const [hash, setHash] = useState();
useEffect(() => {
const handleUrlChange = () => {
setHash(window.location.hash.substring(1));
};
window.addEventListener('hashchange', handleUrlChange);
return () => {
window.removeEventListener('hashchange', handleUrlChange);
};
}, []);
return (
<div>
<a href="#1">1</a>
<a href="#2">2</a>
<a href="#3">3</a>
<a href="#4">4</a>
{hash}
</div>
);
};
ReactDOM
.createRoot(root)
.render(<MyContainer />);
a {
margin: 0.5em;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
You can extract the hash tracking code to a useHash
hook (intended):
const { useState, useEffect } = React;
const useHash = () => {
const [hash, setHash] = useState();
useEffect(() => {
const handleUrlChange = () => {
setHash(window.location.hash.substring(1));
};
window.addEventListener('hashchange', handleUrlChange);
return () => {
window.removeEventListener('hashchange', handleUrlChange);
};
}, []);
return hash;
};
const MyContainer = () => {
const hash = useHash();
return (
<div>
<a href="#1">1</a>
<a href="#2">2</a>
<a href="#3">3</a>
<a href="#4">4</a>
{hash}
</div>
);
};
ReactDOM
.createRoot(root)
.render(<MyContainer />);
a {
margin: 0.5em;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
Now you can trigger your useEffect
with the hash
produced by useHash
:
const MyContainer = () => {
const hash = useHash();
useEffect(() => {
switch (hash) {
...
case 'message':
dispatch(setStep(StepsEnum.Message));
break;
}
}, [hash]);
Answered By - Ori Drori
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.