Skip to content
Advertisement

How to stop a component from setting state before the data fetching?

I have a page and that page has two components. I am fetching the data from root component and passing data to child component using react-redux. I tried to set the fetched data to a state variable that is in child component but it sets data before the fetch is complete in the root component. So, I am getting blank object.

// child component
const [myData, setMyData] = useState<any>(null);
  const data = useSelector((state: { value: any }) => state.value);

  useEffect(() => {
    setMyData(data);
  }, []);

// parent component

  const dispatch = useDispatch();

  useEffect(() => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        dispatch(setData(data));
      });

  }, []);

You can check the whole codebase : https://github.com/Sadiq1029/weather

Can someone help?

Advertisement

Answer

Check if data is not null then update your child state

useEffect(() => {
    if (data) setMyData(data);
}, [data ]);

data.ts

import { createSlice, createSelector } from "@reduxjs/toolkit";

export const dataSlice = createSlice({
  name: "data",
  initialState: { value: null },
  reducers: {
    setData: (state, action) => {
      state.value = action.payload;
    },
  },
});

export const { setData } = dataSlice.actions;

const selectDataSlice = (state: any) => state.data

export const selectValue = createSelector(selectDataSlice, (state) => state.value)

export default dataSlice.reducer;

Background.tsx

import { Container, Flex, Text } from "@chakra-ui/react";
import type { NextPage } from "next";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { selectValue } from "../../states/data";

const Background: NextPage = () => {
  const [myData, setMyData] = useState<any>(null);
  const data = useSelector(selectValue);

  useEffect(() => {
    if (data) {
      setMyData(data);
    }
  }, [data]);

  return (
    <Flex
      minW="100vw"
      minH="100vh"
      alignItems="flex-end"
      style={{
        background: `url('/images/background.jpg') center no-repeat`,
        backgroundSize: "cover",
      }}
    >
      <Flex id="stats" m="8" flexDirection="column" color="white">
        <Text fontSize="xl" fontWeight="hairline">
          {myData ? myData.name : ""}
          {/* {data ? data.name : "hi"}, {data ? data.sys.country : "_"} */}
        </Text>
        <Text fontWeight="bold" fontSize="8xl">
          {/* {data ? Math.round(data.main.temp) : "0"}&deg;C */}
        </Text>
        {/* <Text>{data ? data.weather[0].main : ""}</Text> */}
      </Flex>
    </Flex>
  );
};

export default Background;
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement