Home > Software design >  React Native - How to wait for data then render screen?
React Native - How to wait for data then render screen?

Time:10-03

I'm calling data with a useEffect like this:

useEffect(() => {
    fetchData(id);
  }, []);

Then fetching data and updating state with useReducer dispatch like this:

const fetchData = dispatch => async props => {
  const id = props;
  await axios
    .get(`${URL}?id=${id}`)
    .then(res => {
      const data = res.data;

      const isAuth = data[0].isAuth;
      const dataDetails = data[1].dataDetails;
      const dataTracks = data[2].dataTracks;

      dispatch({type: 'dataDetails', payload: dataDetails});
      dispatch({type: 'dataTracks', payload: dataTracks});
      dispatch({type: 'isAuth', payload: isAuth});
    });
};

Then rendering data like this:

return (
    <SafeAreaView >
      <View >
        {state.dataDetails ? (
          <Text>
            {'@'   state.dataDetails.username}
          </Text>
        ) : null}
        <View/>
      </View>
      <View >
        <FlatList
          data={state.dataDetails.Tracks}
          ListHeaderComponent={ <DataDetails />}
          renderItem={({item}) => <PostTracks item={item} />}
        ></FlatList>
      </View>
    </SafeAreaView>
  );

I'm suppose to display username that i'm getting from data in a header and displaying the rest of the data in a Flatlist but it's not rendering anything.

When I console.log data it first returns undefined, then returns data

How can I make it so that it waits for data to load before it renders the screen?

CodePudding user response:

I think you need create a loading, like this:

const [loading, setLoading] = useState() 

In your useEffect:

useEffect(() => {
    fetchData(id);
  }, [id]);

In fetchData function, you will change loading variable, like this:

const fetchData = dispatch => async props => {
  setLoading(true);
  const id = props;
  await axios
    .get(`${URL}?id=${id}`)
    .then(res => {
      const data = res.data;

      const isAuth = data[0].isAuth;
      const dataDetails = data[1].dataDetails;
      const dataTracks = data[2].dataTracks;

      dispatch({type: 'dataDetails', payload: dataDetails});
      dispatch({type: 'dataTracks', payload: dataTracks});
      dispatch({type: 'isAuth', payload: isAuth});
      setLoading(false)
    });
};

Afterward, you use loading to render the screen:

return (
 {
    loading ? <>loading</>
    : <SafeAreaView >
      <View >
        {state.dataDetails ? (
          <Text>
            {'@'   state.dataDetails.username}
          </Text>
        ) : null}
        <View/>
      </View>
      <View >
        <FlatList
          data={state.dataDetails.Tracks}
          ListHeaderComponent={ <DataDetails />}
          renderItem={({item}) => <PostTracks item={item} />}
        ></FlatList>
      </View>
    </SafeAreaView>
}
    
  );

You can try change this way.

CodePudding user response:

Put your id in dependency array:

useEffect(() => {
  fetchData(id);
}, [id]);

Since your dependency array is empty, the useEffect only runs once.

If you put your variable in dependency array, the useEffect will run again when variable changed. Thus, the view will re-render.

  • Related