Home > Enterprise >  'useEffect' not run only once
'useEffect' not run only once

Time:10-07

================================================================

Thanks everyone, especially Mr.Drew Reese. If you are newbie as me, see his answer.

================================================================

I don't know why but when I console log state data if I use useEffect, it always rerender although state generalInfo not change :/ so someone can help me to fix it and explain my wrong?

I want the result which is the data will be updated when generalInfo changes.

Thanks so much!

This is my useEffect

======================== Problem in here:

  const {onGetGeneralInfo, generalInfo} = props;
  const [data, setData] = useState(generalInfo);

  useEffect(() => {
    onGetGeneralInfo();
    setData(generalInfo);
  }, [generalInfo]);

======================== fix:

 useEffect(() => {
    onGetGeneralInfo();
  }, []);

  useEffect(() => {
    setData(generalInfo);
  }, [generalInfo, setData]); 

this is mapStateToProps

const mapStateToProps = state => {
  const {general} = state;
  return {
    generalInfo: general.generalInfo,
  };
};

this is mapDispatchToProps

const mapDispatchToProps = dispatch => {
  return {
    onGetGeneralInfo: bindActionCreators(getGeneralInfo, dispatch),
  };
};

this is reducer

case GET_GENERAL_INFO_SUCCESS: {
        const {payload} = action;
        return {
          ...state,
          generalInfo: payload,
        };
      }

this is action

export function getGeneralInfo(data) {
  return {
    type: GET_GENERAL_INFO,
    payload: data,
  };
}
export function getGeneralInfoSuccess(data) {
  return {
    type: GET_GENERAL_INFO_SUCCESS,
    payload: data,
  };
}
export function getGeneralInfoFail(data) {
  return {
    type: GET_GENERAL_INFO_FAIL,
    payload: data,
  };
}

and this is saga

export function* getGeneralInfoSaga() {
  try {
    const tokenKey = yield AsyncStorage.getItem('tokenKey');
    const userId = yield AsyncStorage.getItem('userId');
    const params = {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${tokenKey}`,
      },
    };

    const response = yield call(
      fetch,
      `${API_GET_GENERAL_INFO}?id=${userId}`,
      params,
    );
    const body = yield call([response, response.json]);

    if (response.status === 200) {
      yield put(getGeneralInfoSuccess(body));
    } else {
      yield put(getGeneralInfoFail());
      throw new Error(response);
    }
  } catch (error) {
    yield put(getGeneralInfoFail());
    console.log(error);
  }
}

CodePudding user response:

the initial state in redux and state in component is an empty array. so I want to GET data from API. and I push it to redux's state. then I useState it. I want to use useEffect because I want to update state when I PUT the data and update local state after update.

Ok, so I've gathered that you want fetch the data when the component mounts, and then store the fetched data into local state when it is populated. For this you will want to separate out the concerns into individual effect hooks. One to dispatch the data fetch once when the component mounts, the other to "listen" for changes to the redux state to update the local state. Note that it is generally considered anti-pattern to store passed props in local state.

const {onGetGeneralInfo, generalInfo} = props;
const [data, setData] = useState(generalInfo);

// fetch data on mount
useEffect(() => {
  onGetGeneralInfo();
}, []);

// Update local state when `generalInfo` updates.
useEffect(() => {
  setData(generalInfo);
}, [generalInfo, setData]);

CodePudding user response:

in your useEfect you are setting generalInfo and it causes change in the dependency array of useEffect. So, it runs over and over:

  useEffect(() => {
    onGetGeneralInfo();
    setData(generalInfo);
  }, [generalInfo]);

try this instead:

  useEffect(() => {
    onGetGeneralInfo();
    setData(generalInfo); // or try to remove it if it is unnecessary based on below question.
  }, []);

However, I don't understand why you have used setData(generalInfo); in useEffect when you have set it before. does it change in onGetGeneralInfo(); function?

CodePudding user response:

Yow hook has or uses things that are not listed in the dependencies list

useEffect(() => {
    onGetGeneralInfo();
    setData(generalInfo);
  }, [   onGetGeneralInfo, setData,   generalInfo]);

Also let's remember that useEffect is call before the component mounts and after it mounts, so if you add a log it will be printed

  • Related