Home > Back-end >  React userSelector gives undefined value for the first time
React userSelector gives undefined value for the first time

Time:04-12

Im fetching data from api using axios, in the api https:/...?vs_currency=${currency}&... I am trying to assign currency value to api using redux. The problem is useSelector gives the undefined value for the first time and i failed to fetch data from this api. But then useSelector works fine. Error display is https:/...?vs_currency=undefined&...

Here is the redux code

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

export const currencySlice = createSlice({
  name: "currency",
  initialState: {
    currency: "usd", // first i have currency: null. but then i change it to avoid undefined value, but same result
  },
  reducers: {
    selectCurrencyAndSymbol: (state, action) => {
      state.currency = action.payload;
    },
  },
});

export const { selectCurrencyAndSymbol } = currencySlice.actions;
export const selectcurrency = (state) => state.currency.currency;
export default currencySlice.reducer;

Here is the useSelector code

importing stuff ...

function Carousel() {
  const classes = useStyles();
  const [trending, setTrending] = useState("");
  const currencySelector = useSelector(selectcurrency);

  const fetchTrendingCoins = async () => {
    const data = await axios.get(TrendingCoins(currencySelector?.currency));
    setTrending(data);
  };

  useEffect(() => {
    fetchTrendingCoins();
  }, [currencySelector.currency]);
  
  ...

I Also try to directly assign value for the first time

  
    var currencyValue;
    
   useEffect(() => {
    
      currencyValue = !currencySelector.currency
       ? currencyValue === "pkr"
       : currencyValue === "usd";

    currencyValue = currencySelector?.currency;
    
    fetchTrendingCoins();
    }, [currencyValue]);

Here is the useDispatch code

importing stuff ...

function Header() {
  const [currency, setCurrency] = useState("usd");
  const [symbol, setsymbol] = useState("$");

  const dispatch = useDispatch();

  useEffect(() => {
    if (currency === "pkr") setsymbol("Rs");
    else if (currency === "usd") setsymbol("$");

    dispatch(selectCurrencyAndSymbol({ currency, symbol }));
  }, [currency]);

  ....

CodePudding user response:

//Here you can see that your sending in an 
object {
currency: "usd", 
symbol: "$"
}
selectCurrencyAndSymbol({currency, symbol})

Then in your useEffect you will have issues with the way your using setState

 useEffect(() => {
    if (currency === "pkr") setsymbol("Rs");
   //else if (currency === "usd") setsymbol("$");
   //here symbol will be $ as the state wouldnt have updated yet by the 
   //time the dispatch is envoked
    dispatch(selectCurrencyAndSymbol({ currency, symbol }));
  }, [currency]);

Your first soloution is to add symbol to your dependancy array which will cause the useEffect to be run when the symbol is updated

Second solution:

useEffect(() => {
 let symbol = "";
    if (currency === "pkr") symbol = "Rs";
     else if (currency === "usd") symbol = "$"
    dispatch(selectCurrencyAndSymbol({ currency, symbol }));
  }, [currency]);

Then finally in your store state you have

initialState: {
//NOTE: This is not an object at first
    currency: "usd",
  },
reducers: {
selectCurrencyAndSymbol: (state, action) => {
//Here for example the action payload is {currency: "usd", symbol: "$"} 
  state.currency = action.payload;
},

Your solution would be if you want to keep the object approach:

initialState: {
        currency: { currency: "usd", symbol: "$" };
      },
    reducers: {
    selectCurrencyAndSymbol: (state, action) => {
      state.currency = action.payload;
    Or
      state.currency.currency = action.payload.currency
      state.currency.symbol = action.payload.symbol
    },

OR

initialState: {
             currency: "usd", 
             symbol: "$"
          },
 reducers: {
        selectCurrencyAndSymbol: (state, action) => {
          state.currency = action.payload.currency
          state.symbol = action.payload.currency
        },

However if you want to keep it as

initialState: {
        currency: "usd"
      },
//Then just send through the currency in your func like this 
selectCurrencyAndSymbol(currency)

Please note then when you use your selector to get the state how you access the data is dependant on how it is defined so for example //Also just a heads up best practice is to use cam case here for selectcurrency should be selectCurrency

export const selectCurrency = (state) => state.currency.currency;

how we get the data could be const data = useSelector(selectCurrency) either data.currency if we followed the object approach other wise just data will work

I hope this gives you some insight

CodePudding user response:

Did you check the redux store with redux dev tool or console log. Can you see the currency value?

If currency might be null or undefined. Can't you put a if statement before fetchTrendingCoins function in useEffect? If there is no currency don't fetch.

  • Related