React, calling a function before render - reactjs

I have an async function to call before render
(the async function fetches firebase RemoteConfig and I want to use the value when rendering)
Now, I have the following structure
async componentDidMount() {
await remoteConfig.fetch()
}
Problem is that the fetch call is not guaranteed to be called before render (in my test)
How do I make sure to fetch the data before render()?

if you want to execute function before render, I think there are other hooks like getDerivedStateFromProps . But calling api before render is generally not recommended. Using componenDidMount is good, you should structure you code like:
componentDidMount(async () => {const res = await fetch(//your api)})
Once you receive the data, you call this.setState to update your state and react will automatically update the UI

Related

How to reduce API calls in a react functional component?

Overview
The below functional component renders the list of users in a dropdown. In the edit mode, we can change the current user to another user from the list of users.
Expected
The given code is fetching details thrice. I need to reduce it to one.
function UsersListView(props){
const { edit } = props // this is true for this case.
const refreshUsers = useRef(true);
const [error,users,refersh]=useFetchData('/profiles')
useEffect(() => {
if(edit && refreshUsers.current){
const fetchData = async () => {
await refresh();
}
fetchData();
refreshUsers.current = false;
}
},[edit, refresh])
return (
...... JSX CODE TO RENDER USERS
)
}
In the above code, we are making 3 API calls.
In the initial render
When we refresh the data => We fetch the data again. => API called
As refresh is in the dependency of useEffect() hook a re-render occurs then calling useFetchData() => API called.
My attempt
Initially refershUsers.current=false is under await refresh() which got me 8 API calls.
The above-mentioned code still gives me 3 API calls.
I tried moving const [error,users,refersh]=useFetchData('/profiles') inside useEffect() which throws an error. Hooks can't be used inside callbacks.
Queries
Is there a way to reduce the API calls to 1.
Why were the API calls reduced from 8 to 3 when I moved the line refershUsers.current=false outside
Try using a separate useEffect for each dependency. React allows you to use multiple useEffect within the same component.
one of them could be with an empty dependency array for the initial fetch. and then update state or make additional fetch calls as needed in another useEffect

Syncronous state updates using Context API + UseReducer

I'm building a react native app with react navigation, which means I can't pass down props to my components the usual way (they are all nested inside a <Stack.Screen> component from react navigation).
Instead, I'm using the react Context API to pass data down through my component tree.
My problem is that everytime I use dispatch, it seems to act asynchronously. If I do:
const Submit = function () {
//this line is caught by my reducer and the signUpData is added to the state
dispatch({ type: "signUp", signUpData})
axios({ url:'myapiURL', data: state.signUpData, method: "POST" })
}
My post request will be sent with undefined instead of the proper signUpData. Whatever I try to do immediately after a dispatch, it is as if the state has not been updated yet, because dispatch is async.
The problem is that dispatch is not supposed to be async (as far as i understand ? the docs are unclear) and because it doesn't return a promise, I can't use .then() or await/async to make sure the dispatch is complete before my axios or console log happens on the next line.

In Enzyme how to wait for an API call in the componentDidMount method?

We have a React component which we mount with Enzyme:
const component = mount(<App/>);
The component loads data on componentDidMount which we mock with nock:
nock('http://localhost:3100').get(`/api/data`).reply(200, DATA...);
We want to test the value of a label inside the component. However the value is only populated after the data is loaded via the fetch call. How can we wait for the fetch call to finish before writing the expect:
expect(...
You would have to do something like:
Promise
.resolve(mounted)
.then(() => mounted.update())
.then(() => {
expect(label === value); // Just using pseudocode here to denote where to write the expect statement
})
You might still face incorrect behavior here, in which case you can check this thread

React: Fetching data after `componentDidMount`

I have a general question about good practice for React data fetching.
In general, all of the tutorials I have read suggest fetching data in componentDidMount. So my lifecycle looks like this
render
componentDidMount
fetch ... setState
render
Now I have buttons which, when clicked, should fetch more data. But componentDidMount will not be called again. So what is the best practice for calling fetch again after componentDidMount has already been called?
You don't have to put the fecth call in componentDidMount. You can put your fetch in a function outside of componentDidMount, and call it in componentDidMount and call it again after any button action.
componentDidMount() {
this.fetchApi();
}
fetchApi = () => {
//call fetch
}
ComponentDidMount works only one time in component lifecycle - after first render when component is mounting. As I understand, you you need fetch more data by button clicking, so you need something like this:
async loadData() {
const processedResponse = await fetchAsyncFunction()
this.setState ({yourStateParam: processedResponse })
...
render(){
return(
<button onClick={this.loadData}
)
}

Fetch data on Async ComponentDidMount before rendering

In my componentWillMount function, I have an async function getResults that fetches data from a server. I want to pass the response from getResults to the same component on initial load, but I noticed that my component renders before waiting for the data to come back from getResults. How do I make the component wait for the response before having it render? I am using Redux to handle my state.
async componentWillMount() {
const response = await getResults(this.props.category)
}
Async/Await only makes your code look synchronous.
async componentWillMount() {
const response = await getResults(this.props.category)
this.setState({
// use response to set your state.
});
}
Set state is what causes the re-render.
You then use the state to determine if you are in a loading state. If so it may be good to show the user. You also want to handle the default data in the first render. Once you retrieve your response you set the data to the second state.
It's idiomatic React to render your component asynchronously. You'll fetch your data, and set your state accordingly... with a new state, your component will re-render. A common practice it to render the component with a spinner, and when the state is set, re-render with the actual data. At the very least, you can render null until your async request completes and sets your state.
componentWillMount() is invoked just before mounting occurs. It is
called before render(), therefore calling setState() synchronously in
this method will not trigger an extra rendering. Generally, we
recommend using the constructor() instead.
Avoid introducing any side-effects or subscriptions in this method.
For those use cases, use componentDidMount() instead.
This is the only lifecycle hook called on server rendering.
source
You can use componentDidMount() and make the rendering conditional and waiting for the result from the API, and then render it with the result.

Resources