With current version of react-navigation, there are two ways to check if a screen is focused or not, by either (1) calling function isFocused of screen's prop navigation, or (2) hook the component to withNavigationFocused and retrieve prop isFocused.
However, both methods always return true when navigation starts. In my case, I need something triggering only when screen transition ends, i.e. new screen is fully focused. This is to deal with heavy-rendered children, such as camera or map, which should be rendered after screen transition to avoid slow transition animation.
Any idea how to achieve that?
You can try subscribing to the navigation lifecycle events, as described in the docs:
const didFocusSubscription = this.props.navigation.addListener(
'didFocus',
payload => {
console.debug('didFocus', payload);
}
);
Another example usage in this repo
Related
I have a NextJS app with two very different layouts depending on whether it's in landscape or portrait mode.
My parent page is effectively:
<NavWrapper> <MyPage> </NavWrapper>
The NavWrapper component takes care of the portrait v landscape layouts, and passes {children} into two different components. Each of those components provides the layout, and a container, into which the actual page is rendered.
size.isPortrait?
<NavPortrait children={props.children}/> :
<NavLandscape children={props.children}/>
No the problem I'm having is this - Inside 'MyPage' I have a showModal=useState(), which I use to show a pop-up modal. This is working fine. But if I rotate the screen with the modal showing, it disappears. And stays disappeared if I rotate back.
I'm assuming that the change in orientation is causing a fresh instance of 'MyPage' which obviously has the showModal state to the default 'false'.
What's the best way to fix this? Should I have a higher level 'Modal' context? Should I somehow memoise 'MyPage'?
You'll likely need to store the state of showModal at a level higher than MyPage. The code sample you posted indicates that you're rendering a brand new component based on the value of size.isPortrait. You should store the important state at a higher level than your conditional component, and then pass it into the component (either through React Context, props, or some other way.)
If your components do not share any kind of state (or if they do not inherit their state from a singular source), they will always store their state independently.
const [showModal, setShouldShowModal] = useState(false);
return (
size.isPortrait
?
<NavPortrait children={props.children} showModal={showModal} />
:
<NavLandscape children={props.children} showModal={showModal} />
);
I've implemented a Dialog component which displays the values of some state variables.
When the Dialog closes, the state variables are reset to default. The problem is that although the Dialog closes in less than a second, it's still enough time to see that the text has changed.
Is there a way to stop the text from changing until the Dialog has actually closed? I tried setting the dialogOpen state variable to false first, before resetting the other state variables to default, but it didn't help since it happens too fast and React asynchronously batches the state changes anyway.
<Dialog
open = {dialogOpen}
onClose = {() => handleDialogClose()}
... />
handleDialogClose():
const handleDialogClose = () =>
{
setDialogOpen(false)
setStateVariables(DEFAULT_VALUES)
}
I think this issue is general to more components than just the Dialog, since it also happens with text that appears on Snackbar components. A general solution to all of it would be best, but anything will help.
Edit: The Dialog uses a Fade transition, where the timeout.exit delay is about 200ms. Using setTimeout() to delay updating the state variables works, per #technophyle's answer below. The delay passed to setTimeout() can be 0 and the extra time is still enough to prevent the change being seen.
This is a tricky issue to resolve gracefully if your Dialog component has a CSS transition animation.
One solution (though not pretty) if you know the transition duration:
const handleDialogClose = () =>
{
setDialogOpen(false)
setTimeout(() => {
setStateVariables(DEFAULT_VALUES)
}, TRANSITION_DURATION_MS)
}
With react-color https://casesandberg.github.io/react-color/ .
I can use ready-made onChangeComplete function from react-color.
But I wonder how can I create that onChangeComplete by using input type color tag.
I tried onBlur but the color won't change until user clicks or presses tab
On the other hand, using onChange keep firing updates.
Because currently I'm using redux state, so dispatching update continuously when I drag and choose color isn't a good way.
Any ideas how to create onChangeComplete?
It depends on how you'd like to define a change. To prevent continuous updates every time the mouse moves, you'll probably want to update Redux state only when the mouse stops moving. (This seems to be the behaviour on the page you linked to).
You could use the following JavaScript to detect when the mouse stops moving:
let timer;
window.addEventListener('mousemove', function (e) {
console.log('Mouse moving');
clearTimeout(timer);
timer = setTimeout(() => console.log('Mouse stopped'), 300);
});
Then, try putting the above code inside your ComponentDidMount() method and replace console.log('Mouse stopped') with whatever Redux action you want to dispatch!
300 is the number of milliseconds without movement that will trigger the action, which could be changed depending on how sensitive you want your app to feel.
Lastly, remember to remove the event listener in your ComponentWillUnmount() method.
https://github.com/casesandberg/react-color/blob/7ee60d845e5d5e11e4f6ecb895b2d9755c59d09d/src/components/common/ColorWrap.js#L30
Here is the code that how react-color implemented onChangeComplete.
It is hard coded using debounce.
I put the link there for anyone interested in using that solution
I need to propagate state changes to user screen as quickly as possible for some important UI elements, defer other element renderring a bit.
I know about setState's callback, it doesn't help me here.
I think fiber priorities could help me, but I don't know how to use them.
Example:
I have a button that must be disabled immediately after click.
I also have many other slow components that change on that button click.
React batches rendering of the disabled button and other slow components together so the button does not get disabled immediately.
Current workaround is to delay other state changes, to make React immediately disable the button, and only then start to modify other components:
this.setState({ enabled: false }, () => {
this.debounce = setTimeout(() => {
this.props.onModified(value);
}, 200);
})
Is there some explicit way to tell React to be fast to render in some important state changes, without batching them?
(The problem is not only with buttons, but with immediate closing of the modal dialogs as well)
https://codesandbox.io/s/kk4o612ywr
You can use callback function of the setstate, something like this, which will ensures the rendering of the first change. so, your button will get the disabled first and then you can update your state with different operations. using timeout will not be accurate as there is fixed timing which will cause the inaccurate results.
Here is what I did:
this.setState({ enabled1: false },function(){
this.setState(prevState => ({ data: prevState.data + 1 }));
});
Demo
I'm new ot react native and am having a hard time with the idea of not using inheritance, but rather composition.
My scenario: I'm creating a component (focusedTextInput) which shows one InputText. My component simply adds functionality to change the style of the TextInput on focus.
I'm using FocusedTextInput in another component which contains five focusedTextInput and I configure those to only have one character at a time and to auto-skip to the next FocusedTextInput when the character is entered (using the focus() method).
Where I'm running into issues is the my FocusedTextInput does not have a focus method (and I don't want to expose the TextInput).
So do I need to surface all the method that might be used from TextInput on FocusedTextInput or is there a better way?
See this answer React set focus on input after render on stack overflow.
I think this applies to react-native but it does work in the web.
That shows you how to set a ref to a component. And in the CDM set the focus to that component.
To extend how that works so you can set the focus to a specific input (if there are many) is to add a prop called setFocused
Change the CDM to
// Set the focus on first render.
componentDidMount(){
if (this.props.setFocus) {
this.nameInput.focus();
}
}
// focus if the prop changes
componentWillRecieveProps(nextProps) {
if (this.nextProps.setFocus) {
this.nameInput.focus();
}
}