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

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.

Related

How to unmount component with updated context value?

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?

react render state child component vars not updated?

I have a component that is being called, then called again with updated information, but the var topics is not being updated by react. Can someone explain why the first example does not update on the screen, but the second one does? Does it have something to do with the useState call?
App.js calls DisplayQuestions once during initial render, then the page takes in user input and re-renders.
<DisplayQuestionsByTopic topics={topics} />
.....
topics var is NOT updated on screen:
export function DisplayQuestionsByTopic(props) {
console.log(`DisplayQuestionsByTopic`, props.topics)
const [topics, setTopics] = useState(props.topics) //<<<<<<<<
render(<h1>topics.join(',')</h1>)
}
topics var IS updated on screen:
export function DisplayQuestionsByTopic(props) {
console.log(`DisplayQuestionsByTopic`, props.topics)
render(<h1>props.topics.join(',')</h1>) //<<<<<<<<<<<
}
The argument passed to useState is only considered the first time the component renders - that is, on mount. On mount, the prop is put into the topics state. On further renders, changes to the prop don't result in a change to the state because the state has already been initialized to its initial value before.
While you could use useEffect to change the state in the child when the prop changes:
useEffect(() => {
setTopics(props.topics);
}, [props.topics]);
Unless you're using setTopics somewhere, it would make more sense just to render the prop, like you're doing in the final snippet.
If you do need to do setTopics in the child, consider passing down the state setter from the parent instead - that way, all the state is handled in the parent, and you don't have duplicate state holders in different components that need to be synchronized.

How can a child component find if the Parent Component is finished modifying the dom, from it's recieved props

I am working on a library project.
My root component is listening to the redux store. on my initial page visit, the store is not loaded. so it shows no books at first. after about in 1 second (after the books API call finishes) it loads books to the redux store which updates the Dom of the root container with fetched books.
I have a menuBar component which works as a child component of the root component. is getting dom nodes created by the root object [ I use document.getElementByID('ID') ]. I do this in my child components componentDidMount() function. the problem is child Component doesn't rerender after root component rerenders.
so menubar stays empty.
I use redux-persist.
If I refresh the page, the menubar will appear because redux-persist gives values to the redux store from the initial API fetch.
Is there a way to detect if a root component is doing a dom modification and If so is there a way to force update the child Component from the root component.
please comment if you need more information.
You need to pass the data to the child component rather than using a ID lookup.
const Parent = (store) => {
const dataFromRedux = store.parentData
// get your data some how
return (
<div>
<Child data={dataFromRedux} />
<div>
)
}
const Child = ({ data }) => {
// child will now re-render when the data is updated
return <div>{data}</div>
}

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.

How do I pass state between pages using react navigation?

I'm trying to pass state from main page to a details page. The details page changes the parent state successfully by calling function (via props). However, a re-render is not triggered and the details page is not updated (despite it having updated props correctly). How can I pass state to a child page (details) such that it will trigger it to re-render?
It seems like a similar question is asked here
but I don't quite understand it. I'm not using redux as this is a small app.
//Navigator Setup
const AppNavigator = createStackNavigator({
Home: {
screen: Home}
Details: {
screen: Details}
);
//Home page:
this.props.navigation.navigate("Details", {
changeDetails: this.changeDetails
details: this.state.details})
}
//Details page
let details = props.navigation.getParam("details", "n/a");
let changeDetails = props.navigation.getParam("changeDetails", "n/a");
//change things
//render stuff
Passing the data with navigation.navigate won't trigger a re-render since it is passing a copy of the props. You will need to find an other way to send the props so that your component gets aware of the changes.
You can for example connect your component to your redux state (assuming you're using redux). If you are not using redux, you can send a refresh fucntion from your parent component navigate('Child', { refresh: refreshFunction } to the Child
You can then access this function in the child ( via something like this.props.navigation.state.params.refresh();or const refresh() = this.props.navigation.getParam('regresh') ) before the back action. This will trigger updating the parent state to update.
I hope this help you
You have pass the data in correct way but while extracting the data you went wrong
let details = props.navigation.getParam("details", "n/a");
just put this.props
like this
console.log(props.navigation.getParam.changeDetails);
console.log(props.navigation.getParam.details)
console.log is just for debugging purpose you can assign it to any variable And you will receive the data in object form or in json form.set this in constructor, render() or where you want to use this data
as document say:
this.props.navigation.navigate('YOUR TARGET NAME', {
itemId: 86,
otherParam: 'anything you want here',
});
here is the full example,good luck
edit :
in child component in componentDidUpdate() method you must check that if props are changed set new props to state,then component will be re-rendered with new state's:
componentDidUpdate(){
if ('YOUR DATA FROM PARENT' != 'PREVIOUS DATA FROM PARENT SAVED IN STATE'){
this.setState({yourState: 'YOUR DATA FROM PARENT'})
}

Resources