如何在挂钩中比较来自 react redux 状态的值
Posted
技术标签:
【中文标题】如何在挂钩中比较来自 react redux 状态的值【英文标题】:How to compare values from react redux state in hooks 【发布时间】:2021-10-24 00:13:05 【问题描述】:我最近使用 hooks 编写了一个表格组件,每次页面加载时都会对后端进行 API 调用,因此同时会显示一个正在加载的 Spinner,直到有来自 API 的响应。我使用 redux 作为状态管理,所以当有来自 API 的响应时,会调度一个动作并更新状态。 所以这里的问题是,通常在类组件中我们可以比较 prevProps 和 nextProps 使用
componentDidUpdate(prevProps)
if(this.props.someState !== prevProps.someState)
// do something
但我不确定如何使用 Hooks 实现相同的目标。我还提到了这个***问题 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 [];
);
// table component
<Fragment>
loading === true ? <Spinner /> : <TableComponent tableData=tableData />
</Fragment>
因此,每当组件加载时,如果 redux state 中存在任何数据,则会显示该数据,并且不会对 prevProps 和 nextProps 进行比较,因为加载微调器不会显示,并且在新调用的 api 响应之后状态将被更新,新数据将显示在表格中。
更新 1: 这是 dispatch 和 action 以及 reducer 的代码
useEffect(() =>
dispatch(fetchDetails(params.someID));
, [dispatch, params.someID]);
动作文件
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));
;
减速器文件
const initialState =
tableDetails: ,
;
export default function (state = initialState, action)
switch (action.type)
case FETCH_DETAILS:
return
...state,
tableDetails: action.payload,
;
default:
return state;
【问题讨论】:
您是否尝试过使用React.memo? 【参考方案1】:您可以实施简单的验证来实现您想要的。
我会假设你的tableData
有一个id
,然后你可以这样验证:
useEffect(() =>
// don't fetch the same table
if(tableData?.id !== params.someID
dispatch(fetchDetails(params.someID));
, [dispatch, params.someID, tableData?.id]);
更新 1
要将以前的表格数据与新提取的数据进行比较,您可以在操作创建器中执行此操作:
-
将
loading
状态移动到 redux 存储区。
使用 getState
函数,这是 action creator 接收的第二个参数(假设您使用的是 redux-thunk)
在调度操作之前,将新的tableData
与存储中的数据(上一个tableData
)进行比较。
检查并更新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));
;
【讨论】:
问题不在于获取/调度操作。它关于在表格中显示加载图标,每次页面加载时,一旦从 API 获取响应,响应就可以显示在表格中。如果 redux 状态有一些旧数据,则显示旧数据而不是加载图标。我想根据 api 响应比较 prevprops 和 nextprops 来设置加载状态真/假。 你使用 redux-thunk 吗?【参考方案2】:正确的做法是使用redux reselect包https://github.com/reduxjs/reselect。 Redux 团队推荐它。
reselect 是专门为这种场景设计的。它还在引擎盖下使用了记忆。您可以制作自定义选择器并在这样的场景中使用它们。
您可以像这样为所有重新选择功能制作一个单独的文件
//select file (eg: selectors.js)
import createSelector from "reselect";
const tableDetails = state => state.common.tableDetails;
function checkDataFunction(details)
if (
details.data &&
details.status === true
)
return
loading: false,
data: details.data
else if (
details.data &&
details.status === false
)
return
loading: true,
data: []
return
loading: true,
data: []
;
//redux selector
//enables you to make your own custom selector
export const checkData = createSelector(
tableDetails,
checkDataFunction
);
现在在您想要使用它的主组件文件中,只需导入它并将其用作任何其他选择器
//main component file (eg: App.js)
import checkData from './selectors';
export default function App()
const tableData = useSelector(checkData);
useEffect(() =>
//continue with your logic here
,[tableData.loading])
//...
【讨论】:
【参考方案3】:尝试使用 redux 工具包中的 redux-reselect 包来为此类任务构建您自己的选择器。如果您想以 redux 方式管理状态,这是一个方便的工具。 另外我建议按照YouTube tutorial 来设置和使用 redux-reselect。
【讨论】:
【参考方案4】:您如何将数据从存储区分派回该组件? 将其包装到 useEffect 调用中。
这是一个使用 useDispatch 挂钩的示例。
Need clarification for react + react-redux hooks + middleware thunk+ fetching API
【讨论】:
嘿,谢谢你的回答,我已经添加了 dispatch 和 action 以及 reducer 代码。你能看一下吗?以上是关于如何在挂钩中比较来自 react redux 状态的值的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 thunk 在 react-redux 挂钩中进行异步调用?
如何使用 thunk 和 useDispatch(react-redux 挂钩)从操作中返回承诺?
如何在数组依赖中正确使用 useEffect 挂钩。我从 redux 商店传递了状态,但我的组件仍然无限渲染