Why react-native routers use state instead of props? - react-native

There is an official react-native example regarding routing which uses props instead of state.
However all other router component libraries use state instead of props. Especially, the libraries that have prepared for Flux and Redux usages.
What is the main idea of state usage in router components?

The reason why they use navigator=this.props.navigator in this example is that this is a child component, where a parent component is passing down its navigator to the child through props. You generally do not pass down state directly into a child component, you pass down a prop that could be used in "getInitialState".
https://facebook.github.io/react/tips/communicate-between-components.html
Here we see that this is simply the syntax used to pass a prop from parent to child. We want to pass the navigator between different components so that the app is consistent, they are all using the same navigator to navigate between different pages.
Just a warning though, when passing props as state to a child component, note it should be clear that it's only for initialization.

Related

React-Native - lifting state up in functional components

I am trying to share the state from child components to parent component , not using state management , all the components are functional components , how can I do that without using state management like redux or context API ? I have checked the listing state up all the the examples and documentation are in class components , please help me with the same ,thanks
Sharing state between components is really all about prop drilling, that is to say, passing props a parent component receives to its child component. Because props are passed on with JSX there is minimal difference between prop drilling in a functional component and a class component.
The biggest difference would be at the top level component where the state and its modifier function are passed to the first child component. This difference is very trivial, e.g
// accessing state variable and state modifier in class component
<CustomComponent
user={this.state.user}
setUser={
newUser=>this.setState(prev=>({...prev,user:newUser})
}
/>
// accessing state variable and state modifier in functional component
<CustomComponent
user={user}
setUser={setUser}
/>
Even so, this react doc gives a basic example of efficient prop drilling that uses functional components

Cannot update props passed via react navigation

I have a container where the API calls happen. I need to pass the response I get to another component which is not the child of the above container. I can't pass in props like how you usually do since it is not a child component of the above container. What I do is, I pass the response to the above container's child component and from there I use :
this.props.navigation.navigate('Whatever',{
reason: this.state.reason
});
To pass in the reason as prop to the "Whatever" component. Now, the problem is this "reason" prop does not get updated when it changes in the container from where it is being passed.
Now, I am aware that since we are not passing props like how they are usually passed that's why we won't be able to get the updated props in whatever component. I am aware that I might have to change the structure of my app as well, but I cannot afford that right now.
Is there any way via which I can update the reason prop in the whatever component?
Thanks in advance.
You can use params in react navigation
--updating params https://reactnavigation.org/docs/params/#updating-params
--passing params https://reactnavigation.org/docs/params/#passing-params-to-a-previous-screen
--passing params to nested component https://reactnavigation.org/docs/params/#passing-params-to-nested-navigators

<router-view> components inside other <router-view>s (same component)

I currently have the following problem with nested <router-view>s in my app and I want to know if this is even the right way to do it.
I have a navigation.vue route component with child routes configured in the router.
In this component, I have multiple <router-view>s (in a v-for loop).
Every router-view has its own link and if you click on it, the clicked container which holds the router-view will start a transition and reveal the content (the page.vue component).
To fire the transition before confirming the navigation, I listen for the beforeRouteUpdate() hook.
However, I now want to add other navigation components inside this navigation, so that I have something like that:
<navigation>
<page/>
<page/>
<navigation>
<page/>
<page/>
</navigation>
<page/>
</navigation>
The hook to open the sub-navigation seems to work - but if I try to open a page on the second level, the navigation component can't get the $refs that belong to itself. I see the beforeRouteUpdate() hook of the first level navigation being called. I think that's to be expected because it's still in the background, holding the second level navigation and its pages.
What can I do to only use the functionality of the second level navigation when it's opened?
Should I make some checks in the beforeRouteUpdate() hook, and are they both fired?
I'm probably confused because I don't know if the component is being reused or something - in my understanding it should be a second instance of the component.
I'm also using <keep-alive> around the <router-view>s - so if that's a problem and things work differently with that, I'd also be glad to get a hint.
Thanks!
I’m not sure if this will fix your problem but in this vue school video they talk about the Vue Router not always picking up on changes if the same component is being used. You can handle it by adding a key to the router-view like <router-view :key=“$route.path” />. Then any change to the path will trigger a reload of the component. Maybe you can experiment with adding keys to your nested <router-view>s?
I solved it this way:
Both beforeRouteUpdate() hooks are called, so I had to make sure which of the existing navigations should do the work. The upper level navigations skip the hook.
I also needed some checks to only render the navigation in the <router-view> if it is in the $route.match array of the current route.

How to pass props on React-Navigation so the navigated component can re-render when those props are changed

im trying to navigate from component A to B passing props this way (as options):
this.props.navigation.navigate("B",{
retrievePlayingNow:this.props.retrievePlayingNow, // props come from component C
skipSong: this.skipsong, // this is a function
});
}
so when i call a function 'skipSong' it changes the props on component C (which is a father component of A)props on A changes but on component B props remain the same and it doesn't re-render to show the new info. Is there any other way i can do this using React-Navigation?
This is where a state management libraries comes into action.
Well, I use redux. Here you can store the data in the global store which can be accessible by any of the components.
So put the variable retrievePlayingNow into the redux store from C component, and access it by B component. So when C (or anyone) changes the value of that variable, all those components using accessing that variable (including B) will re-render.
Another advantage of using any state management library is that you don't need to make a hierarchy of components to pass props as you have done C -> A -> B. All you can do is dispatch the variable into the store from C and directly access it by B
You can use DeviceEventEmitter to add listener events to re-render without using redux.

How to check when a React Native component has finished RE-rendering?

I am currently re-rendering Child components within a Parent component based on a state change and I need to know when the child component has completely mounted and re-rendered on screen. Here's a quasi-example:
<Parent>
{ this.state.showChild1 ? <Child1/> : <Child2/> }
</Parent>
The general procedure for responding after state change would be using componentDidUpdate(prevProps, prevState) however, this lifecycle event only fires after state has updated without considering the effects of what the state change would update within the <Parent> component.
The problem I'm encountering then is that although state has completely updated, the new Child component is not yet available because it hasn't actually finished re-rendering yet. Is there a way to check when the Child components have re-rendered?
You could pass a callback into the component (sth like isMounted()) and call it in the child in the componentDidMount and componentDidUpdate lifecycle hook.
If you need this with arbitrary components you could iterate over them with React.Children.map(see docs) and add the lifecycle hooks on the fly (this is a bit error prone and you would need to have class components)