Home > database >  react native useSelector not refreshing
react native useSelector not refreshing

Time:07-05

I'm trying to create a pie chart by making changes to my variable using Redux on React-Native, but even if the dispatch operation is successful in my variable, when I use useSelector, there is a one-time change. Even if my next dispatch operation is successful, useSelector does not refresh the data and I cannot see it on the screen.

Home screen:

import React from 'react';
import {ScrollView, View, Text, Button} from 'react-native';
import {useSelector} from 'react-redux';

import PieCard from '../components/PieCard/PieCard';
import DailyInfo from '../components/DailyCard/DailyInfoCard';
import CustomHeader from '../components/CustomHeader/CustomHeader';

const Home = ({navigation, route}) => {

  //I'm pulling data with useSelector
  const selectorData = useSelector(item => item.userData);
  const selectorData2 = useSelector(item => item.dailyData);

  const [userInfo, setUserInfo] = React.useState(selectorData);
  const [dailyData, setDailyData] = React.useState(selectorData2);
  const dayControl = dailyData.time.split('/');
  const days = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
  ];
 
  //I want to update when there is a change in useSelector
  React.useEffect(() => {
    setUserInfo(selectorData);
    setDailyData(selectorData2);
  }, [selectorData, selectorData2]);

  //preparing data for pie

  const setPieData = (remaining, consumed) => {
    return {
      dataRate: [
        {
          x:
            consumed > remaining
              ? ' '
              : `${Math.round(100 * (remaining - consumed)) / 100} g`,
          y: consumed > remaining ? 0 : remaining - consumed,
        },
        {x: `${consumed} g`, y: consumed},
      ],
      color: ['#ff0000', '#80ce48'],
    };
  };
  //return my app
  return (
    <ScrollView style={{flex: 1, backgroundColor: '#eeeeee'}}>
      <CustomHeader title={days[new Date().getDay()]} navigation={navigation} />
      <View style={{flex: 1, marginHorizontal: 10}}>
        {userInfo.daily_calori > 0 ? (
          <DailyInfo
            calories={Math.round(100 * (userInfo.daily_calori / 4)) / 100}
            fat={Math.round(100 * (userInfo.daily_fat / 4)) / 100}
            protein={Math.round(100 * (userInfo.daily_protein / 4)) / 100}
            carbohydrate={
              Math.round(100 * (userInfo.daily_carbohydrate / 4)) / 100
            }
          />
        ) : (
          <Text style={{flex: 1, alignItems: 'center'}}>
            You must enter your information on the profile page.
          </Text>
        )}
        {dailyData.protein > 0 && dayControl[0] === `${new Date().getDay()}` ? (
          <View>
            <PieCard
              data={setPieData(userInfo.daily_calori / 4, dailyData.calories)}
              header="Calories"
              title1="remaining"
              title2="consumed"
            />
            <PieCard
              data={setPieData(userInfo.daily_fat / 4, dailyData.fat)}
              header="   Fat"
              title1="remaining"
              title2="consumed"
            />
            <PieCard
              data={setPieData(userInfo.daily_protein / 4, dailyData.protein)}
              header="Protein"
              title1="remaining"
              title2="consumed"
            />
            <PieCard
              data={setPieData(
                userInfo.daily_carbohydrate / 4,
                dailyData.carbohydrate,
              )}
              header="Carbohydrate"
              title1="remaining"
              title2="consumed"
            />
          </View>
        ) : null}
      </View>
    </ScrollView>
  );
};
export default Home;

My reducer:

import AsyncStorage from '@react-native-async-storage/async-storage';


export default function (state, action) {

  let userData = state.userData;
  let dailyData = state.dailyData;
  let weeklyMenu = state.weeklyMenu;
  let montly = state.montlyData;

  switch (action.type) {
    case 'USER_INFO':
      userData = action.payload.data;
      try {
        const jsonValue = JSON.stringify(userData);
        AsyncStorage.setItem('user_info', jsonValue);
      } catch (err) {
        console.log('user set err', err);
      }
      return {...state, userData};

    case 'ADD_FOOD':
      let {food, year, month, date, day, meal} = action.payload;
      let time = `${day}/${date}/${month}/${year}`;
      const dayControl = dailyData.time.split('/');

      if (time !== dailyData.time) {
        dailyData = {protein: 0, fat: 0, carbohydrate: 0, calories: 0};
        montly.days.push(time);
        if (montly.days.length > 31) {
          montly.days.shift();
          montly.data.shift();
        }
        if (`${day}` === dayControl[0] && `(${date}` !== dayControl[1]) {
          weeklyMenu.week[day] = [[], [], [], []];
          weeklyMenu.foodId[day] = [[], [], [], []];
        }
      }

      dailyData.time = time;
      console.log('zaman', dailyData.time);
      dailyData.protein  = Math.round(100 * food.full_nutrients[0].value) / 100;
      dailyData.fat  = Math.round(100 * food.full_nutrients[1].value) / 100;
      dailyData.carbohydrate  =
        Math.round(100 * food.full_nutrients[2].value) / 100;
      dailyData.calories  =
        Math.round(100 * food.full_nutrients[3].value) / 100;

      let monthData = [
        dailyData.protein,
        dailyData.fat,
        dailyData.carbohydrate,
        dailyData.calories,
      ];

      weeklyMenu.week[day][meal].push(food.food_name);
      weeklyMenu.foodId[day][meal].push(food.nix_item_id);

      let montlyIndexDay = montly.days.indexOf(time);
      montly.data[montlyIndexDay] = monthData;

      AsyncStorage.setItem('weeklyMenu', JSON.stringify(weeklyMenu));
      AsyncStorage.setItem('dailyData', JSON.stringify(dailyData));
      AsyncStorage.setItem('montly', JSON.stringify(montly));
      
      console.log('!update data:\n', weeklyMenu.week[day][meal]);
      //i can see update my data 
      return {...state, weeklyMenu, dailyData, montlyData: montly};

    case 'REMOVE_FOOD':
      food = action.payload.food;
      year = action.payload.year;
      month = action.payload.month;
      date = action.payload.date;
      day = action.payload.day;
      meal = action.payload.meal;
      time = `${month}/${date}/${year}`;

      let indexFood = weeklyMenu.week[day][meal].indexOf(food[0].food_name);

      if (indexFood > -1) {
        weeklyMenu.week[day][meal].splice(indexFood, 1); // 2nd parameter means remove one item only
        weeklyMenu.foodId[day][meal].splice(indexFood, 1);
      }

      dailyData.protein -= food[0].nf_protein / 4;
      dailyData.fat -= food[0].nf_total_fat / 4;
      dailyData.carbohydrate -= food[0].nf_total_carbohydrate / 4;
      dailyData.calories -= food[0].nf_calories / 4;

      monthData = [
        dailyData.protein,
        dailyData.fat,
        dailyData.carbohydrate,
        dailyData.calories,
      ];

      montlyIndexDay = montly.days.indexOf(time);
      montly.data[montlyIndexDay] = monthData;

      AsyncStorage.setItem('weeklyMenu', JSON.stringify(weeklyMenu));
      AsyncStorage.setItem('dailyData', JSON.stringify(dailyData));
      AsyncStorage.setItem('montly', JSON.stringify(montly));
      
      console.log('!update data:\n', weeklyMenu.week[day][meal]);
      //i can see update my data 

      return {...state, weeklyMenu, dailyData, montlyData: montly};

    default:
      return state;
  }
}

Below is my app screen. When I get the weeklyMenu variable for the first time, the graph appears, but the pie graph does not change when there is a change in the weeklyMenu yield.

enter image description here

CodePudding user response:

Let's start in your component:

If you do

const selectorData = useSelector(item => item.userData);
const [userInfo, setUserInfo] = React.useState(selectorData);

you are using the selectorData as the initial state to userInfo. That means, no matter how often selectorData changes later, userInfo will never update.

You seem to kinda get around that by using the useEffect, but seriously: why don't you just skip the local component state and just do

const userInfo = useSelector(item => item.userData);

?

But the real problem is in your reducer.

Let's put together what you do there:

let montly = state.montlyData;
...
montly.days.push(time);

Since montly is just a reference to state.montlyData, that is exactly the same as doing state.montlyData.days.push(time) - which is something you are never allowed to do in legacy Redux reducers: you are not allowed to mutate the state. The same goes for the montly.days.shift() and most obviously the montly.data[montlyIndexDay] = monthData;.

You would have to write a lot of complicated immutable logic to make this work in a legacy Redux reducer and honestly, it wouldn't help readability.

But now I have used the word "legacy" two times already, so this is probably the most important point:

You have probably being following outdated tutorials.

In modern Redux, as it is officially recommended by the Redux team, you should not be writing switch..case reducers any more since about 2019.

If you write a "modern Redux" createSlice reducer, inside that you can mutate state as you please.

So my recommendation would be that you follow the official Redux tutorial to learn how to use modern Redux - since that is in general a lot easier to use and not suspectible to mutation bugs like you are experiencing right now.

For more information, please read Why Redux Toolkit is how to use Redux today.

CodePudding user response:

@phry Thank you for your reply and the information you provided. For now, I made some improvements in the reducer in the form of state.montlyData.days.push(time) . I will learn the modern version.

const selectorData = useSelector(item => item.userData);
const [userInfo, setUserInfo] = React.useState(selectorData);

Just const selectorData = useSelector(item => item.userData); I wanted to try it with useEffect because I couldn't see the data change on the screen using the line. So I created a variable using useState but the result did not change as you know.

  • Related