使用SWR和Redux一起是否正确或是良好的实践?

11
我正在使用SWR
在我的代码中,我将两者结合使用,如下所示。
const vehiclesStates = useSelector(({ vehiclesStates: state }) => state); // REDUX
const response = useFetch("/vehicles/states") // SWR
const dispatch = useDispatch(); // REDUX

// REDUX
useEffect(() => {
  if(response.data) dispatch(VehiclesStatesActions.setVehiclesStates(response.data.result))
}, [response.data, dispatch]);

if(response.error) return <div>ERROR - {response.error.toString()}</div> // SWR
else if(!response.data) return <div>LOADING</div> // SWR

// If there is a return I render my component
return (<></>)

在上面的摘录中,我使用SWR(与axios集成)返回的数据将我的组件状态设置为redux中。这样,在任何需要使用相同数据的其他组件中,我只需使用redux的useSelect导入它。
这样做可以...
const vehiclesStates = useSelector(({ vehiclesStates: state }) => state);

我认为使用useFetch比仅仅调用SWR更实用,因为它可以在每个需要使用该数据的组件上调用。我的问题是:这种方式的使用是否正确?或者会影响性能或其他方面吗?谢谢。

2
为什么你要在SWR中使用redux?Swr已经为你处理了所有的缓存工作。如果你需要本地状态管理,我建议你使用API上下文。Redux会给你带来更多的复杂性。 - syllmz
4
我之前使用过上下文,但是在使用redux组织和存储结构后,我感觉更舒适了 :P - Alexssander Leal Luz
3个回答

25

我认为这有点多余,你可以更好地使用其中一种,SWR旨在将缓存用作本地状态,因为该状态存在于服务器上,所以更适合并且无需繁琐地管理每个状态操作,就像您必须使用Redux明确调用API调用每次调度操作一样。

同时使用两种技术会使SWR失去意义,最好还是只使用Redux。一个好的原则是使用SWR来管理存储在服务器上的状态,并使用Redux来管理本地状态。

我可以想到一些场景,当您需要进行非常复杂的数据操作并且需要频繁修改和删除信息时,我认为这种情况将使用Redux和SWR的mutate函数的混合。


1
从某种角度来看,SWR通过其缓存向您的应用程序提供全局状态,并能够自动使缓存失效并刷新新数据,这是一个很好的答案。 - steviesh

11
你可以使用swr与redux一起使用,这并不冗余。因为有两种类型的状态:UI StateServer Caching State。 UI状态的一个示例是模态框的打开或关闭。服务器缓存状态,我们调用api,存储结果并将该结果缓存以在客户端使用。swr处理服务器缓存状态。
在redux早期,没有缓存。然后出现了一些库,在next.js中是swr,在react中是react-query库。 Redux-toolkit有自己的api缓存实现。
我认为在React-16时代,我们获得了上下文API。React上下文本身不是状态管理工具。它只是传递数据的一种方式。如果您使用useStateuseReducer,它就成为了状态管理工具。将React Context与自己的钩子组合使用,您可以替换redux。在您的钩子函数中,应使用swr。我在这里解释了如何结合react-context、hooks和swr创建完整的状态管理工具:全局状态管理和Next.js

0

后端响应可能包含一个项目列表。SWR方法将强制重绘使用列表中的项目的所有元素,或者创建一组智能匹配器和/或上下文,以告诉DOM的哪一部分应该更新或不更新。

Redux也需要一些努力来保持props的稳定性。然而,可以使用提供的useSelector + shallowEqual来提取仅需最小化的内容。这是List组件的id列表和Card组件中按id显示的行列表。

请查看代码。在我看来,这两种方法并不是直接竞争对手。

话虽如此,请记住,有库(恰巧是Material-UI)为您管理列表。如果您使用其中之一,请使用其推荐的方法来优化重绘(如果需要)。

    import { FC } from "react";
    import { shallowEqual, useSelector } from "react-redux";
    import useSWR from "swr"

    interface CardInfo {
      id: number;
      name: string;
      price: number;
    };
    type RootState = Array<CardInfo>;

    declare const fetcher: () => Promise<CardInfo[]>

    const CardView: FC<CardInfo> = (p) => (<pre>{JSON.stringify(p)}</pre>);

    const CardById: FC<Pick<CardInfo, "id">> = ({ id }) => {
      const card = useSelector((rootState: RootState) => rootState.find((c) => c.id === id), shallowEqual)
      if (typeof card === "undefined") {
        return null;
      }
      return <CardView {...card} />
    }

    export const ListSwr: FC = () => {
      const { data } = useSWR(
        "/api/cards",
        fetcher,
        /*{compare: NO FANCY COMPARE HELPS 
          WHEN ONLY ONE OF MANY ITEMS CHANGED}*/
      );
      if (!Array.isArray(data)) {
        return null;
      }
      return (<>
        {data.map((c) => (<CardView key={c.id} {...c} />))}
      </>)
    }

    export const ListFromStore: FC = () => {
      const ids = useSelector((rootState: RootState) => rootState.map(e => e.id), shallowEqual)
      return (<>
        {ids.map((id) => <CardById key={id} id={id} />)}
      </>)
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接