How to unmount component with updated context value? - reactjs

So I have a parent component that would be the dashboard that displays conditionally a child component that subscribes to a websocket service. When the user completes a form inside of the child component the data is set to the ws service and I get a response and the user is "connected" to the ws, thus far everything works fine. The problem I have is that if the user starts the connection and then navigates to another page (like the profile page) the ws connection doesn't stop and the user still appears as connected.
I've been using useEffect to handle unmounting components but I get a problem with it. In order to unsubcribe from the ws I need the stompClient (from stompjs that renders the ws) and the data object (the data I send to the ws which contains info from user) and I save these objects in a context to use them globally.
This is the parent component where I need to disconnect the ws.
import { useStateProfConsultFilterValue } from '../../../context/profConsultFilterState';
...
const [{stomp, data}, dispatch] = useStateProfConsultFilterValue();
useEffect(()=>{
return () => {console.log(data};
},[]);
But when it unmounts I get an empty array (which is the default value from the context. If I listen to changes in useEffect I get the updated value from the child component but I fires every time the data changes and I need it to run only when the component unmounts.
import { useStateProfConsultFilterValue } from '../../../context/profConsultFilterState';
...
const [{stomp, data}, dispatch] = useStateProfConsultFilterValue();
useEffect(()=>{
return () => {console.log(data};
},[data]);
/// fires multiple times when data changes
I can't handle it from the child component because based on the value I get from the ws it unmounts and mounts constantly. I tried having two useEffects, one for storing the data in a local state every time it changes and another that logs that local state on unmount, but I get the same resutl. I also tried passing a function to and from the child component with the values but it doesn't work.
How can I get the updated context state on the parent component? Or how can I get it to log the correct data only once when the component unmounts?

Related

Best Practice to toggle Childcomponent from Parent

I created a toast notification in React which is Toggleable via the timeNotification function. For testing purposes, I used a button in the same Component to toggle the notification. All the notification does is to set a CSS class to "active" and after 5 seconds remove it.
const timeNotification = () => {
setShowNotification(true);
setShowProgressBar(true)
setTimeout(() => {
setShowNotification(false)
}, 5000);
setTimeout(() => {
setShowProgressBar(false)
}, 5300)
}
my goal is to make this Component triggerable in my React app whenever I need it. For example, when I require the user to log in to my website and the backend server is not reachable it is supposed to use my Notification component to send an error to the user.
What is the best practice to do so?
The first idea was to simply pass a function from the child to the parent component which is a bad practice because as far as I know functionality should always be passed down and never upwards.
The second idea was to toggle the component via useEffect
useEffect(()=> {
timeNotification()
}, [])
This approach only works once. But after the Component is rendered for the first time, it just vanishes (gets moved out of the user's view). This approach would work if Id make the component un render after 5 seconds and rerender it as soon as a new error occurs which is also a bad practice.
I just found a solution, I still don't know if it's the best practice however it works. I did use the useEffect hook in the Child component.
useEffect(() => {
timeNotification();
}, [props.refresh])
its triggered by the Parent via props and useState
const [showLoginError, setShowLoginError] = useState<number>(0);
setShowLoginError(prev => prev + 1)
when ever the parent increases the showLoginError the Notification useEffect gets triggered

React/Redux: Component renders with old props

I am using useEffects return() to clean up the state data in Redux when leaving a page. However, when changing view to another page, a child component that fetches new data still shows the old data from Redux for a short time before the new data shows up. The child component fetches data with a useEffect(), with an empty dependency list.
The clean up useEffect looks like this:
useEffect(() => {
return () => {
props.clearState()
}
}, [])
Where clearState() resets the redux-store to its initial values. The Redux Devtools shows that the state actually is cleared, but the child-component still renders with old props for a short time. I read that useEffect is asynchronous, could it be that the useEffect therefore is to slow? And how would you solve this without using the return() from useEffect?
Any help is appreciated, thanks!

How to force refresh of GrandParent component from grandchild component with React hooks in SPFx

In the main component of a SPFx web part, I have a data load running in a React.useEffect
const [jobsGets, setJobsGets] = React.useState(0);
React.useEffect(() => {
{Some code to get data from SharePoint}
});
}, [jobsGets]);
So a refresh will happen when the value of "jobsGets" will change, right?
This component calls another component that calls another and the last has an event that should refresh by changing "jobsGets".
If I write a fanction and pass it down the props of each generation's component,
It ends running in the main component forever. So this is not a good solution.
How do I setJobsGets(jobsGets+1); from the grandchild components?
Any hint is welcome.
Thank you
you are likely updating jobs at grandChild with useEffect, that runs on mount and every update. if you pass a second empty array [] param, this update will run only after first render if that's your specific case, avoiding retriggers:
// at some granchild
useEffect(() => { ...logic here }, [])
if useEffect should run after on specific param's update, you pass that param as argument to the array. useEffect will run only on changes for the params dependencies set on [].
useEffect(() => { ...logic here }, [param])
you may also look at useContext for passing down state better at deep tree.

How to update child component after props are changed in parent component

I have component TopicsView where I have property called choosenTopicId which I change on button click. Inside this component I have child component
<TopicViewOnSide TopicId={this.state.choosenTopicId} />
Inside TopicViewOnSide I use TopicId in componentDidMount() when I'm sending request from axios (HTTP GET) to get topic data from the server and then component TopicViewOnSide renders. My problem is when I change choosenTopicId by clicking button in TopicView, props are changed and it's good. But the child component doesn't rerender when the props are changed and I have old topic data because the child component didn't call componentDidMount() and there was no request to server. Can I somehow call the method componentDidMount() when the props are changed so the request from axios will be send and my data will be updated ?
You're looking for componentDidUpdate() which gets triggered after every state or prop change. The componentDidMount() method only runs a single-time.
You can do something like:
componentDidUpdate(prevProps){
if(this.props.blaw !== prevProps.blaw){
...execute your logic
}
}
That creates a check to do something only when props change.

React Navigation: How to update child state when parent state gets updated?

The data of parent is passed to child via:
this.props.navigation.navigate("foo", {data: data});
Whenever one navigates to any screen, the current state of objects is sent as props to the navigated component.
Having said that, the navigate function should be associated with a function/component placed in render(). So, if data is updated, render() gets called again and you're navigated to the new screen with updated data.

Resources