Suppose I have two screens:
Screen A
Screen B
I am initially landed on Screen A. When I click on a Button I navigate to Screen B. When I press Back Button, I am again navigated to Screen A.
I want to call an action creator when I am navigated to Screen A as mentioned in above scenario.
I just want to know that which lifecycle event will be called every time when a screen is presented.
Isn't there some event like componentWillAppear()?
Note: I am using react-native with react-navigation for navigation.
This can now be done with plain react navigation via their listeners:
In your Component A:
componentDidMount = () => {
this._componentFocused();
this._sub = this.props.navigation.addListener(
'didFocus',
this._componentFocused
);
}
componentWillUnmount() {
this._sub.remove();
}
_componentFocused = () => {
this.setState({dataToShow});
}
React Navigation docs - Lifecycle
When you navigate from one screen to another, the first screen will not be unmounted, but still on the stack, just hide in the background.
What you need might be componentDidFocus, but it's currently in design not avaiable yet, see react-native open issue #51.
You can try this alternative way: react-navigation-addons. With this you can have events focus & blur which may suit your needs.
If you use react-native-navigation, you can listen for appearance events: https://wix.github.io/react-native-navigation/#/screen-api?id=listen-to-visibility-events-globally
Related
so I am coding a simple app with react-navigation and I want to code this:
- Home (Tab)
- Profile (Tab)
-- User info (Stack screen)
--- Edit user info (Stack screen) - (screen with input to edit name, email etc...)
When I click save on the EditInfo screen I have a button on the right side of the header Done, this button should navigate back to the UserInfo screen where you can see the updated details.
BUT!
Everything works but when I click Done on the EditInfo screen, it navigates back to Home! Why is that?
Thanks for help
Could you please put the code of the service screen where you call the goBack function, it could be helpful. Generally you just call
You are either using the wrong Navigator comp or your requirements are not clear. Basically, You would like to use the StackNavigator for your desired behavior.
The catch is, DrawerNavigator is used to build up a drawer menu. If you swipe from the left you'll see your navigator drawer containing all of your screens as you can see in the image below
If you add a button on your screen like below, you'll see your menu open.
<Button title="MENU" onPress={() => this.props.navigation.navigate('DrawerOpen')} />
The conclusion is, whenever we use DrawerNavigator we always go back to initial route, which is whatever we defined as the first item or using the initialRouteName key of the second param of the DrawerNavigator.
It's only the StackNavigator that supports this stacking order you would like to achieve, as the name suggests itself.
What you can do is to wrap a new StackNavigator inside one of the screens of the DrawerNavigator. For example:
const AppNavigator = DrawerNavigator({
drawer1: {
screen: drawer1,
}
});
const drawer1 = StackNavigator({
one: { screen: one },
two: { screen: two },
three: { screen: three },
});
Maybe this answer would help you.
In a nutshell: maybe you need to specify backBehaviour param in your Tabs navigator.
First of all, a shout out to Yoav the developer of React Uploady. It's a very helpful library with all kinds of great fancy features (chunked uploads, upload progress hooks, etc).
I have a question about using the asUploadButton hook. Here's my use case: within my app, a user can choose from several places to upload a batch to. This is done by selecting a global dropdown that specifies the upload destination. Since user error is a real thing, I need to show them a confirmation screen. This is easy to do the first time they hit the "upload" screen: a state variable keeps track of whether they have confirmed they're in the right place, conditionally rendering either the confirmation component (if they haven't confirmed), or the Uploady component (custom UploadButton) if they have confirmed.
But the requirement is that we show the confirmation every time. Once a user has uploaded a batch, they should still be shown the confirmation if they click on that custom UploadButton again. I tried passing an onClick into the asUploadButton component, but that callback is actually called after showFileUpload - and I want to show an interstitial modal once the button is clicked but before showFileUpload is called. Is there any hook to call a method before showFileUpload? Or am I approaching this completely wrong? Advice of any kind is very appreciated.
as answered here on the react-uploady discussions page:
In your case, I think a custom button will make more sense. In the end, asUploadButton is a very simple component that mainly does one thing and that is, call showFileUpload available from the UploadyContext.
You could create your button component that implements the logic (show confirmation) and when user approves calls the showFileUpload.
You get access to the method using:
import { useUploady} from "#rpldy/uploady"
//...in your component:
const { showFileUpload } = useUploady();
const onClick = () => {
//custom logic
showFileUpload();
};
I have two components, component A and component B
In Component A , i have two buttons
Like in picture, I have Start and Stop buttons. If I click on Start button Stop button will be enabled and Start will be disabled.
Now my problem is if I click on Start button and If I navigate to some other page, and if I comeback to page, Start button is getting enabled and Stop button is getting disabled.
Expectation is if I click on Start button, it should still be in disabled mode and Stop button should be on enabled mode when navigated to another component and come back to this component
<button #click="start" class="start-button" icon-left="play" :disabled="!allowStart">Start</button>
<button #click="stop" class="stop-button" icon-left="stop" :disabled="allowStart">Stop</button>
data() {
return {
allowStart: true,
};
}
start() {
this.allowStart = false;
}
stop() {
this.allowStart = true;
}
Can anyone help me on this. appreciated the help and response in advance.
It sounds like the component is being destroyed and re-created when you navigate away and back. In this case, there is no way for the component to remember what the value of allowStart was.
Either you have to re-design the component architecture so that this particular component persists when you are navigating, or you need to use some kind of global state management system. The best option would probably be by using vuex. If you use vuex to store the state of allowStart, then when the component is re-created, you can read the value of the state.
If for some reason you don't want to use vuex, you could also use the browser's localStorage
Im using react-navigation for react-native. Is there an option to make that inactive tab screens get unmounted like unmountInactiveRoutes: true in DrawerNavigator?? I cant find something like unmountInactiveRoutes for BottomTabNavigator.
I have two stacknavigators inside a BottomTabNavigator and I want to unmount them automatically.
BottomTabNavigator
Stack1
Screen
Screen
Stack2
Screen
Screen
You can unmount screens in bottom tab by adding option in navigation screenOptions (or in Tab.Navigator screenOptions):
unmountOnBlur: true
You can do it in Tab & Drawer Navigations but not in Stack Navigation.
And you can also add unmount individual screen by adding same option in Tab or Drawer Screen option.
So I don't know if you can unmount components that are inactive personally I did not find it however this is my workaround withNavigationFocus(FocusStateLabel)
and if isFocused is false. returning null. So this will give you more or less what you are looking for. If isFocused is true, you'll render what you usually render. If false you'll return null. resulting in the unmounting of your components
Some reference https://reactnavigation.org/docs/en/with-navigation-focus.html
I tried Ubaid’s answer it works. But you can try this one too:
Use
import {useIsFocused} from '#react-navigation/native';
const isFocused = useIsFocused();
useEffect(() => {
// Do whatever you want to do when screen gets in focus
}, [props, isFocused]);
It works perfectly fine.
I found two way unmount.
First method is just trigger the unmount using useFocusEffect. With my experience this is not completely unmount component. It just trigger only unmount function to unsubscribe events.
https://reactnavigation.org/docs/function-after-focusing-screen/#triggering-an-action-with-a-focus-event-listener
Second method is completely unmount component when the navigating. This one is working as react unmount.
https://reactnavigation.org/docs/bottom-tab-navigator/#unmountonblur
<Tab.Navigator screenOptions={{unmountOnBlur: true}}>
</Tab.Navigator>
In your tab screens
const unMount = ()=>{
//unmount what you want
}
useEffect(()=>{
return unMount;
},[])
Modify your code with this
Every time you perform a render in React.js, the UI scrolls to the top of the page.
JSFiddle: http://jsfiddle.net/bengrunfeld/dcfy5xrd/
Any nifty or reactive way to stop that?
E.g. If a User scrolls down the page, then pushes a button which causes a Render, the UI would stay in the same scroll location as before.
// Forces a render which scrolls to top of page
this.setState({data: data});
UPDATE: Why does the UI scroll to the top for some renders, but not others?
Ok if anyone read this , in my case the problem wasn't any of above. You must try first suggestions on above any way. I did everything including preventDefault() but didn't help me. The problem was ; using styled-components. Because, styled-components give a random classname every render. So it resets scroll. I gave the class name from css and solved my problem.
#floydophone answered this one on Twitter.
https://twitter.com/floydophone/status/608129119025561600
#bengrunfeld #reactjs you forgot preventDefault() on your link handlers
Wanted to add here for those who are not using anchor tags, preventDefault will not save you. As bizarre as it is, for me it was related to rendering my child components inside a div with
display:table > display:tablecell
For some reason the child component's scroll position is lost in this situation when there is any re-render. Problem vanished when I switched to flexbox (display:flex).
If render trigger scrolling to the top it usually means some UI component is changing its dimension because of the state, this can be fixed by adding a minimum width/height
This could be happening because of the change in redux state, which will show the changes everywhere in the code where it is getting used. Try making the change using the local state of that component on action of which, the page is getting scrolled.
2022 Hacky Solution:
I couldn't find a way to completely prevent the scrolling on the re-render. preventDefault didn't help, and I didn't have access to the specific element structure, but I did have the className of the scrolling element.
useEffect(() => {
const el = document.getElementsByClassName('my-classname')?.[0];
const newTimeoutRef = setTimeout(() => el?.scrollTo(0, scrollTop), 50);
return () => clearTimeout(newTimeoutRef);
}, [scrollTop]);
Then you set the scrollTop (as a component state) inside the event that was previously causing the scroll to top.
The hack here is that setTimeout, which basically gives the DOM time to scroll to the top before calling your el.scrollTo, it flashes a bit, but it was the best solution that worked for me.