reactjs - 如何从 useEffect 访问当前的 redux 状态?

标签 reactjs react-redux react-hooks use-effect

我有一个从数据库中获取的对象列表(在我的例子中为“相册”)。我需要编辑这些对象。 在 useEffect Hook 的编辑组件中,我启动了使用其 ID 获取所需专辑的操作。这个 Action 有效。然而,在同一个 useEffect 中,我试图获取触发操作 redux 状态之前的更改。现在我面临问题 - 我所获取的只是之前的状态。 如何在useEffect中实现当前redux状态的获取?

我在这里看到了类似的问题,但是没有一个答案对我的用例有帮助。

我正在使用 redux-thunk。

编辑组件。问题出现在 setFormData 中 - 它从 reducer 中获取先前的状态,而不是当前的状态。它似乎是在 getAlbumById 更改状态之前触发的:

//imports

const EditAlbum = ({
  album: { album, loading},
  createAlbum,
  getAlbumById,
  history,
  match
}) => {
  const [formData, setFormData] = useState({
    albumID: null,
    albumName: ''
  });

  useEffect(() => {
    getAlbumById(match.params.id);

    setFormData({
      albumID: loading || !album.albumID ? '' : album.albumID,
      albumName: loading || !album.albumName ? '' : album.albumName
    });

  }, [getAlbumById, loading]);

const { albumName, albumID } = formData;

  const onChange = e =>
    setFormData({ ...formData, [e.target.name]: e.target.value });

  const onSubmit = e => {
    e.preventDefault();
    createAlbum(formData, history, true);
  };

  return ( //code );
};



EditAlbum.propTypes = {
  createAlbum: PropTypes.func.isRequired,
  getAlbumById: PropTypes.func.isRequired,
  album: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  album: state.album
});

export default connect(
  mapStateToProps,
  { createAlbum, getAlbumById }
)(withRouter(EditAlbum));

行动:

export const getAlbumById = albumID => async dispatch => {
  try {
    const res = await axios.get(`/api/album/${albumID}`);

    dispatch({
      type: GET_ALBUM,
      payload: res.data
    });
  } catch (err) {
    dispatch({
      type: ALBUMS_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status }
    });
  }
};

reducer

const initialState = {
  album: null,
  albums: [],
  loading: true,
  error: {}
};

const album = (state = initialState, action) => {
  const { type, payload } = action;
  switch (type) {
    case GET_ALBUM:
      return {
        ...state,
        album: payload,
        loading: false
      };
    case ALBUMS_ERROR:
      return {
        ...state,
        error: payload,
        loading: false
      };
    default:
      return state;
  }
};

将不胜感激任何帮助/想法

最佳答案

您应该将效果分成 2 部分,其中之一是在专辑 ID 从路线更改时加载专辑:

const [formData, setFormData] = useState({
    albumID: match.params.id,
    albumName: '',
});
const { albumName, albumID } = formData;

// Only get album by id when id changed
useEffect(() => {
    getAlbumById(albumID);
}, [albumID, getAlbumById]);

当数据到达时设置 formData 状态:

// Custom hook to check if component is mounted
// This needs to be imported in your component
// https://github.com/jmlweb/isMounted

const useIsMounted = () => {
  const isMounted = useRef(false);
  useEffect(() => {
    isMounted.current = true;
    return () => (isMounted.current = false);
  }, []);
  return isMounted;
};

// In your component check if it's mounted 
// ...because you cannot set state on unmounted component
const isMounted = useIsMounted();
useEffect(() => {
  // Only if loading is false and still mounted
  if (loading === false && isMounted.current) {
    const { albumID, albumName } = album;
    setFormData({
      albumID,
      albumName,
    });
  }
}, [album, isMounted, loading]);

当开始获取相册时,您的操作应将“loading”设置为 true:

export const getAlbumById = albumID => async dispatch => {
  try {
    // Here you should dispatch an action that would
    //  set loading to true
    // dispatch({type:'LOAD_ALBUM'})
    const res = await axios.get(`/api/album/${albumID}`);

    dispatch({
      type: GET_ALBUM,
      payload: res.data
    });
  } catch (err) {
    dispatch({
      type: ALBUMS_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status }
    });
  }
};

更新检测为何在不应调用 useEffect 的情况下调用 useEffect:

您能否用此输出更新问题?

//only get album by id when id changed
useEffect(() => {
  console.log('In the get data effect');
  getAlbumById(albumID);
  return () => {
    console.log('Clean up get data effect');
    if (albumID !== pref.current.albumID) {
      console.log(
        'XXXX album ID changed:',
        pref.current.albumID,
        albumID
      );
    }
    if (getAlbumById !== pref.current.getAlbumById) {
      console.log(
        'XXX getAlbumById changed',
        pref.current.getAlbumById,
        getAlbumById
      );
    }
  };
}, [albumID, getAlbumById]);

关于reactjs - 如何从 useEffect 访问当前的 redux 状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58112704/

相关文章:

javascript - 如何在孙子组件中设置或更新数组的状态

javascript - 如何监听 "ref"对象变化?

javascript - 重新选择 - 如何找出哪个参数发生了变化?

reactjs - 如何在用于设置状态值的同一函数中访问更新的状态值

reactjs - 卸载 react 钩子(Hook)中的循环行为

javascript - 使用react实时显示 Node 模块的数据

javascript - 在 chrome 扩展中使用 redux

css - 如何编辑 webpack 以在 React 应用程序中使用 SCSS?

reactjs - 如何在 React 中设置背景图像适合屏幕

reactjs - React.js 中的页面崩溃(读取未定义的属性)