React Hook setState not set on promise - react-native

I'm using the Contentful CMS JS SDK and the code below does not update my React Hook state. It's more of a promises combined with react hooks combined with React render issue - I believe. I understand that the promise sets the hook value when it is resolved at a later time, but by that time my component already rendered with the initial data (empty string), so if this is the case, how can I make my component re-render when the react hook state is set with the correct value from the promise, so that my Button displays it.
Any help appreciated. Thanks
Problem lies within here.
...
import client from 'contentful'
const [name, setName] = useState('')
client.getEntry(data.fields.store.sys.id)
.then(entry => setName(entry.fields.name))
.catch(console.error)
console.log('STORE URL', name) // name is not set
...
<Button title={name} /> // name still not set
....

I just tried your code and it seems to work for me. :)
https://codesandbox.io/embed/react-hooks-demo-e4wgo
I think you should use useEffect though as described in this article.

Related

onWillFocus React Native v6 Replacement?

I want to clear errorMessage, when we navigate from Sign in to Sign up and vice-versa, for that I tried using onWillFocus but it has been deprecated.
Can anyone suggest me the replacement of onWillFocus?
You can use the original useEffect hook prescribed which gets triggered when a screen is loaded and when a state changes. You can either pass [] parameters so it only runs once or you can use a state to check it.
useEffect(() => {
// do you work here
}, []);

Is there a way to reload a screen in React-Native one time after it loads?

I have a react native screen with a joystick component I made but on first load up the joystick doesn't work as intended but works perfectly fine when page is reloaded. Is there any way to set it to reload once quickly one time when it opens?
This sounds more like a bug in your code. You should try to locate the issue and resolve it. However, you could use useEffect() to call a state update as a temporary solution:
const [reload, setReload] = useState(false);
useEffect(() => {
setReload(true)
}, []) // <- no dependencies

How to make api calls when component is loaded multiple times

I need to fetch products each time a user navigates the products screen of a react native app being built with expo. I found out that the component lifecycle hook : componentDidMount is called just once. This is an issue because if the products are updated on the backend / API, if the componentDidMount is not called again when the user visits the product page again, they won't see latest products which defeats the purpose of the app. How may i approach this ?
Thanks
Use componentDidUpdate() method. This will execute automatically before render() method gets triggered.
Please read this to know about the life cycle of react-native.
Call a function inside componentDidUpdate() like this
componentDidMount()
{
this.loadInitialState();
}
and then do your API call and set state in loadInitialState() function. Hope this will work
Hope it helps .feel free for doubts.
You can add a navigation listener: Subscribe to updates to navigation lifecycle
this.props.navigation.addListener(
'didFocus',
() => {
this.getData()
}
)
use WebSocket for realtime application

Whats wrong with 'react-redux.connect()' parameters?

Moving sample redux app from react to react-native.
If I pass non-empty params to react-redux 'connect' function app will crash with
on snack with message about parameter is not a function
on real device (android) about context is text and should be placed in 'Text' component
Simular code works fine on react.
On react native sample - 'connect' with empty parameters will not crash - props just will be empty
Full sample here: https://snack.expo.io/#aaronright/reduxtests
I made this change to your snack, and it seems to run fine on the ios/android simulators.
const actions = {
changeFirstName: actionChangeFirstName,
changeSecondName: actionChangeSecondName,
};
const mapDispatchToProps = dispatch => ({ actions: bindActionCreators(actions, dispatch) });
const AppComponent = connect(
mapStateToProps,
mapDispatchToProps,
)(App);
I also added onChangeText={(text) => this.props.actions.changeSecondName(text)} to your text inputs, changing Second to First for the first name input, so that they would update state. Everything is working for me on those two simulators.
That being said, what exactly is the issue you are having? Connect requires the first param, mapStateToProps, to function, but does not require the second param, mapDispatchToProps. You can pass lodash._ for the first param if you really dont need it

Accessing navigator in Actions with React-Native and Redux

Using React-Native (0.19) and Redux, I'm able to navigate from scene to scene in React Components like so:
this.props.navigator.push({
title: "Registrations",
component: RegistrationContainer
});
Additionally I'd like to be able push components to the navigator from anywhere in the app (reducers and/or actions).
Example Flow:
User fills out form and presses Submit
We dispatch the form data to an action
The action sets state that it has started to send data across the wire
The action fetches the data
When complete, action dispatches that the submission has ended
Action navigates to the new data recently created
Problems I'm seeing with my approach:
The navigator is in the props, not the state. In the reducer, I do not have access to the props
I need to pass navigator into any action that needs it.
I feel like I'm missing something slightly simple on how to access Navigator from actions without sending in as a parameter.
In my opinion the best way to handle the navigation with Redux is with react-native-router-flux, because it can delegate all the navigation logic to Redux:
You can change the route from the reducer;
You can connect the router to the store and dispatch its own actions that will inform the store about route changes (BEFORE_ROUTE, AFTER_ROUTE, AFTER_POP, BEFORE_POP, AFTER_DISMISS, BEFORE_DISMISS);
An example
Here is an example on how easily you can save the currently focused route in the store and handle it in a component (that will be aware of being focused):
1. Connect a <Route> to Redux
Connecting a <Route> to Redux is easy, instead of:
<Route name="register" component={RegisterScreen} title="Register" />
you might write:
<Route name="register" component={connect(selectFnForRegister)(RegisterScreen)} title="Register" />
You can also simply connect the component itself in its own file like you usually do.
2. Connect a <Router> to Redux
If you need to inform Redux of the navigation status (i.e. when you pop a route) just override the <Router> component included in react-native-router-flux with a connected one:
import ReactNativeRouter, { Actions, Router } from 'react-native-router-flux'
const Router = connect()(ReactNativeRouter.Router)
Now when you use a <Router> it will be connected to the store and will trigger the following actions:
Actions.BEFORE_ROUTE
Actions.AFTER_ROUTE
Actions.AFTER_POP
Actions.BEFORE_POP
Actions.AFTER_DISMISS
Actions.BEFORE_DISMISS
Take a look at this for an example.
3. Catch the interested actions in your reducer
For this example I have a global reducer (where I keep the information needed by all my app) where I set the currentRoute:
case Actions.AFTER_ROUTE:
case Actions.AFTER_POP:
return state.set('currentRoute', action.name)
Now the reducer will catch every route change and update global.currentRoute with the currently focused route.
You also can do many other interesting things from here, like saving an history of the navigation itself in an array!
4. Update your component on focus
I'm doing it on componentDidUpdate of my component of the route named payment.
If global.currentRoute is payment and the previous global.currentRoute was different, than the component has just been focused.
componentDidUpdate(prevProps) {
const prevRoute = prevProps.global.currentRoute
const currentRoute = this.props.global.currentRoute
if (currentRoute === 'payment' && prevRoute !== currentRoute) {
this.props.actions.doSomething()
}
}
P.S.: Remember to check currentRoute === 'payment', otherwise you'll start doSomething() on every route change!
Also, take a look a the README.md for learning other stuff about the integration with Redux.
Hope it helps, long live Redux!
Maybe you could pass the information about title and component in an action and the component with the navigator can then push the right scene with the information of the state.