In react native after componentDidMount() its not call again when you navigate to other screens and return to your component (screen). so react native navigation suggest do it by bellow JS codes:
componentDidMount() {
this._Reload = this.props.navigation.addListener('focus', () => {
//do something to reset component
});
}
componentWillUnmount() {
this._Reload();
}
but now I get this error: undefined is not an object (evaluating 'this.props.navigation.addListener') because I use my component in a tab component(nested). how can I add a focus to my component to refresh?
I think I must do it by prop drilling.
I would suggest passing parent screen navigation object (so that you will have focus listener) via context and then in your tab component set the listener to that parent navigation.
Check this for ref on how to pass data to your tab component : Passing params to tab navigator React Navigation 5
Alternatively for a functional component you can use this hook: useFocusEffect from #react-navigation/native
Related
In my code I have a problem with unmount a component. I am using drawer-navigator and when i navigating between drawer-screens the previous screen is not dying and when i open that screen again everything is still there.
But i want to re-render or unmount and mount the component again when i navigate between drawer-screens. Is there a way for that? Or how can i make my component unmount manually? I know there is a lot of question about this but i couldn't find that i want.
My react native version is 0.63
react navigation never destroy the screen. Its mean your screen will never unMount or when you go back it will never remount (didMount). To Perform such see the example below
import React, { useCallback } from 'react';
import { useFocusEffect } from '#react-navigation/native';
const Home = () => {
useFocusEffect(
useCallback(() => {
// Do something when the screen is focused
return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
return <Home />;
}
Reference : Navigation Lifecycle
You should check this page of react-navigation documentation
Consider a stack navigator with screens A and B. After navigating to
A, its componentDidMount is called. When pushing B, its
componentDidMount is also called, but A remains mounted on the stack
and its componentWillUnmount is therefore not called.
Conclusion, the screens are not detroyed and re-created everytime you navigate, it's by design.
If you want to execute some code when you leave or open again a page you should use the lifecycle events presented in the same documentation
I have a react native component which contains both WillFocus and componentDidMount functions.
My Questions is, if I navigate to this component which function is getting triggered first? 'WillFocus' or 'componentDidMount'
Sample code is showing below
class Notifications extends Component {
static navigationOptions = {
header: null
}
constructor(props) {
super(props);
const{navigation}=this.props
this.state = {
highlightHome : true,
highlightNotifications: true,
}
}
willFocus = [this.props.navigation.addListener(
'willFocus',
payload => {
console.log('willFocus')
}
)]
componentDidMount() {
console.log('componentDidMount')
}
}
React Navigation emits events to screen components that subscribe to them.
componentDidMount:
This method is called once all our children Elements and our Component instances are mounted onto the Native UI. When this method is called we now have access to the Native UI (DOM, UIView, etc.), access to our children refs and the ability to potentially trigger a new render pass.
willFocus:
the screen will focus.
By definition, willFocus will be called after ComponentDidMount because it mounted all the UI components.
componentDidMount call first, but in the next time (back or something...) just willFocus call
how to force render our component when props changes?
how to force render parent component when child component's props changes?
i searched a lot but all solutions are deprecated in new React version.
in my any pages (Route exact path="/post/:id" component={post}) for example (siteUrl/post/1) i am getting (:id) from props (this.props.match.params) and that works.
but when i am in single page component (Post) and this Route (siteUrl/post/1) when i am passing new Props to this component (:id).
props will changes but single component and parent component Will not re render...
You may be using componentDidMount method.
componentDidMount() is invoked immediately after a component is
mounted (inserted into the tree). Initialization that requires DOM
nodes should go here. If you need to load data from a remote endpoint,
this is a good place to instantiate the network request.
but you need to use componentDidUpdate.
componentDidUpdate() is invoked immediately after updating occurs.
This method is not called for the initial render.
You can also use state and other React features without writing a class.
read more: https://reactjs.org/docs/hooks-effect.html
To make both parent and child re-render you need to path prop from parent to it's child.
// parent using
<Parent someProp={{someVal}} />
// parent render:
render() {
const { someProp } = this.props
<Child someProp={{someProp}} />
}
this will surely re-render both components, unless you stated another logic in componentShouldUpdate
in your case Router looks like a parent for Parent so you should only path :id as a prop.
Make sure Router is at the top level, right under the App
Important is ,that you initialise the someVal of the child first in the constructor
public static getDerivedStateFromProps(
nextProps,
nextState
) {
let { someVal } = nextProps;
if (nextState.someVal !== someVal) {
return {
initialVal,
someVal: someVal
};
}
return null;
}
After it will rerender on prop changes because the state changes
I am implementing a react page with route info/:id. From this page, there are various URLs which are navigated by NavLink.
For example: if current route is localhost:3000/info/1 and there are links localhost:3000/info/2 and localhost:3000/info/3, clicking on those links will load the page I'm currently on i.e: localhost:3000/info/1. While tracking for props changes, url is getting changed briefly but it's again loading the same page. What shall I do to route to same component with different parameters?
Thanks in advance!!!!!!
You should track your page updates in componentDidUpdate lifecycle method or useEffect hook.
Class components:
componentDidUpdate(prevProps) {
if(prevProps.match.params.id !== this.props.match.params.id){
// do something
}
}
Functional components:
useEffect(() => {
// do something
}, [props.match.params.id]);
Here's how you achieve same via React hooks and functional components:
useEffect(() => {
//do something
}, [props.match.params.id]);
I noticed that whenever I navigate to another page using the navigate props available to my component, it triggers a re-render of the component and componentDidMount is being called whenever I navigate to a screen that has rendered before.
For instance, when I navigate a user to their profile page and they decided to go back to the dashboard, the dashboard component which has been initially rendered is being rendered again and componentDidMount is being called thereby slowing down the application.
import { StackNavigator } from 'react-navigation';
const Routes = StackNavigator({
home: {
screen: HomeScreen
},
dashboard: {
screen: Dashboard
},
profile: {
screen: Profile
}
},
{
headerMode: 'none',
});
In my component I navigate the user with this.props.navigation.navigate('ScreenName')
I would appreciate any help to stop the component from re-rendering when navigating back to it. Thanks
I would have a state variable in your constructor that keeps track if you navigated. State is only relevant to the current component. So if you navigate to 'ScreenName' multiple times, the stack builds and each ScreenName component has its own state.
constructor(props)
super(props)
this.state = {
navigatedAway : false
}
Then before you navigate to your 'ScreenName' screen update the state
this.setState({
navigatedAway : true
},
() => {
this.props.navigation.navigate('ScreenName');
}
);
Use syntax above to make sure state isUpdated THEN navigate. Then like Dan said in comments above if your function shouldComponentUdate have a condition statement.
shouldComponentUpdate(newProps){
// return true if you want to update
// return false if you do not
}
* Side Note *
When you navigate I don't believe the component is unmounted. You could verify this by simply printing to console. Correct me if I am wrong though, I am fairly new to react native.
componentDidMount() {
console.log("COMPONENT_CONTENT_MOUNTED")
}
componentWillUnmount({
console.log("COMPONENT_CONTENT_UNMOUNTED")
}
If you are using React Navigation 5.X, just do the following:
import { useIsFocused } from '#react-navigation/native'
export default function App(){
const isFocused = useIsFocused()
useEffect(() => {
//Update the state you want to be updated
} , [isFocused])
}
If I understand your question correctly, when you navigate away, the component is unmounted.
When you navigate back, it must be re-mounted, hence re-rendered.
In general, any UI change necessitates a re-render. No way around that - It's kind of "by definition".
You might be able to cache the page.
Or use the reselect library to cache expensive to obtain data, so the calculations for re-rendering are quick and minimal.
If react/react-native thinks the props have changed (in an already mounted/rendered component), it will also re-render, but you can influence this decision via shouldComponentUpdate().
Just add React.memo to your export of component that reload each time.
So instead of
export default component
you would have:
export default React.memo(component);
Which does a comparison of props and only re-renders if props change (so not on navigate but on actual changes, which is what you want)