如何比较钩子中反应 redux 状态的值

jar*_*vak 7 javascript reactjs react-redux react-state-management react-hooks

我最近使用 hooks 编写了一个 table 组件,每次页面加载时都会对后端进行 API 调用,因此同时会显示一个加载 Spinner,直到 API 响应。我使用 redux 作为状态管理,所以当有来自 API 的响应时,会调度一个动作并更新状态。所以这里的问题是,通常在类组件中我们可以使用比较 prevProps 和 nextProps

componentDidUpdate(prevProps){
  if(this.props.someState !== prevProps.someState){
      // do something
    }
}
Run Code Online (Sandbox Code Playgroud)

但我不确定如何使用 Hooks 实现相同的目标。我还提到了这个 stackoverflow 问题 How to compare oldValues and newValues on React Hooks useEffect?

但是这个解决方案在我的情况下似乎不起作用。我确实尝试过创建自定义钩子usePrevious并创建一个ref 来比较当前值,但这并没有解决我的问题。

这是我的部分代码。

let loading = true;

let tableData = useSelector((state) => {
   
    if (
      state.common.tableDetails.data &&
      state.common.tableDetails.status === true
    ) {
      loading = false;
      return state.common.tableDetails.data;
    }
   
    if (
      state.common.tableDetails.data &&
      state.common.tableDetails.status === false
      
    ) {
      loading = true;
    }
    return [];
  });

Run Code Online (Sandbox Code Playgroud)
// table component

<Fragment>
  { 
   loading === true ? <Spinner />  :  <TableComponent tableData={tableData }/>
   }
</Fragment>

Run Code Online (Sandbox Code Playgroud)

因此,每当组件加载时,如果 redux state 中存在任何数据,则会显示该数据,并且不会对 prevProps 和 nextProps 进行比较,因为不会显示加载微调器,并且在响应新调用的 api 状态之后将是更新和新数据将显示在表中。

更新 1: 这是 dispatch 和 action 以及 reducer 的代码

 useEffect(() => {
    
    dispatch(fetchDetails(params.someID));

  }, [dispatch, params.someID]);

Run Code Online (Sandbox Code Playgroud)

动作文件

export const fetchDetails = (data) => (dispatch) => {
  axios
    .post(
      `${SomeURL}/fetchAll`,
      data
    )
    .then((res) => {
      if (res.data.status) {
        dispatch({
          type: FETCH_DETAILS,
          payload: res.data,
        });
      }
    })
    .catch((err) => console.log(err));
};

Run Code Online (Sandbox Code Playgroud)

减速器文件

const initialState = {
  tableDetails: {},
};

export default function (state = initialState, action) {
  switch (action.type) {
    case FETCH_DETAILS:
      return {
        ...state,
        tableDetails: action.payload,
      };

    default:
      return state;
  }
}


Run Code Online (Sandbox Code Playgroud)

Har*_*tha 3

您可以实施简单的验证来实现您想要的。我假设你tableData有一个id,那么你可以这样验证:

useEffect(() => {
    // don't fetch the same table
    if(tableData?.id !== params.someID {
      dispatch(fetchDetails(params.someID));
    }
}, [dispatch, params.someID, tableData?.id]);
Run Code Online (Sandbox Code Playgroud)

更新1

要将先前的表数据与新获取的表数据进行比较,您可以在操作创建器中执行此操作:

  1. 将状态移动loading到 redux 存储。
  2. usegetState函数,这是动作创建者收到的第二个参数(假设您正在使用 redux-thunk)
  3. 在分派操作之前,将新数据tableData与存储中的数据(上一个tableData)进行比较。
  4. 进行检查并更新loading状态。

export const fetchDetails = (data) => (dispatch, getState) => {
  axios
    .post(
      `${SomeURL}/fetchAll`,
      data
    )
    .then((res) => {
      if (res.data.status) {
        const prevTableData = getState().tableData;
        
        // compare prev and new table data
        if(isDiff(prevTableData, res.data) {
            // Do something...
        }
        dispatch({
          type: FETCH_DETAILS,
          payload: res.data,
        });
      }
    })
    .catch((err) => console.log(err));
};
Run Code Online (Sandbox Code Playgroud)