【问题标题】:What is the recommended approach for large react app with react-query?对于带有反应查询的大型反应应用程序,推荐的方法是什么?
【发布时间】:2022-01-04 16:55:29
【问题描述】:

我最近开始使用函数式组件和 react-query 来使用 react,它一直运行良好,只是我不清楚如何正确组织组件。

我习惯于设计组件的方式是拥有一个顶级组件,该组件执行所有数据访问并通过道具将数据传递给它的子组件。它还将各种回调处理程序传递给子组件,以便在需要操作时,顶级组件将更新数据并将新数据传递给子组件。所以在我的例子中,所有对 useQuery()、useMutation() 的调用都驻留在顶级组件中,但这会使代码变得非常混乱。但它更像是一个包含各种子组件的页面,这些子组件仅显示数据或帮助用户与数据交互。

function Page(){
  const [page, setPage] = useState(1)
  const [size, setSize] = useState(10)

  const persons = useQuery('persons', async ()=> await getPersons(page, size))
  const addPerson = useMutation(async (args)=> { 
   const {id, name, desc} = args
await addPerson(id, name, description)
})
  const person = useQuery('persons', async ()=> await getOnePerson(page, size), { enabled : false })

  const addPersonCB = (id: number, name: string, desc: string)=> {
    addPerson.mutate({id, name, desc})
  }
 // complex if/else logic to choose child components 

第二种方法是将 react useQuery() 和 useMutation 分散到需要的组件中。为了进一步简化事情,如果渲染逻辑很复杂,每个组件都会有一个父组件来执行操作并将数据作为 prop 传递。

function PersonCard(props: PersonCardPropsType){
   const {data, isLoading, isError, error} = useQuery(`personQuery${props.id}`, getPerson)

   if(isLoading)
      return <Wait />
  
   if(isError)
     return <Error reason={error} />

   const record = data as PersonModel
   return ( <PersonCardUI person={record} />) 
}

并且可能有网格,表格等的组件,每一个都以成对的形式出现

<PersonEditor />, <PersonEditorUI />, <PersonGrid />, <PersonGridUI /> 

在这种情况下,调用分散在代码中的任何地方。我想知道

  1. 对于大型项目,推荐哪种方法?为什么?
  2. Redux 和 react-Query 的混合搭配好吗?例如,网格的页面大小和页码应该放在 redux 中,也许?
  3. 可以在某些地方使用纯 axios/fetch 和 redux/react-query 吗?这被认为是一种不受欢迎的做事方式?

【问题讨论】:

  • 所有这些都归结为意见。对于#1,这取决于您的需求;我们在需要的地方使用 r-q 钩子,并且不会通过组件层向下传递事物(但如果它是共享数据,我们也会为其中的一些使用上下文)。 #2 当然,虽然我很少将 Redux 用于纯 UI 问题——这就是 state 的用途。 #3 使用任何在上下文中最有意义的东西。
  • 不久前我在使用 useSwr 时遇到过同样的问题。我采用了混合方法。我的useSwr 周围有自定义钩子,我尽可能地提升状态。然后我将 redux 用于全局状态,例如 auth user。另外,当提升状态变得太麻烦并且 redux 似乎有点矫枉过正时,我使用了 react 的 context api。我也有过滤器,其状态在 url 本身中。总而言之,这种混合方法似乎效果很好。
  • 所以你说的是,“没有方法是错误的,这完全取决于一个人的需求”,但如果这是我们在大型项目中遵循的方法,那么它会不会在一段时间后变成代码混乱3-4 位开发人员正在根据自己的意见工作?
  • 对...我认为您总是可以争论给定方法的优点/缺点,但我怀疑是否存在一种做事方式。这将是一个判断电话。我确实认为一个人无法摆脱 redux,并且喜欢将它用于全局状态,只要它被谨慎使用。

标签: reactjs typescript react-hooks react-functional-component react-query


【解决方案1】:

通常认为在您需要的地方使用useQuery 是一种最佳做法。分离成容器/展示组件虽然仍然可行,但自从 hooks 出现以来,它在很大程度上已被弃用。使用 redux connect / mapStateToProps,最佳实践。现在,即使在 redux 中,您只需在您需要的地方调用 useSelectoruseDispatch。这在 react-query 中没有什么不同。

Mark Erikson 就这个主题发表了精彩的演讲:Hooks, HOCs and tradeoffs,我完全可以推荐观看。

在需要的地方使用 react-query 钩子不仅可以避免 prop 钻取,还可以让 react-query 更轻松地保持数据最新,因为越来越多的观察者(=调用 useQuery 的组件)正在安装。这也是为什么当您想要自定义重新获取行为时最好设置 staleTime 的原因。我已在React Query as a State Manager 中详细介绍了这一点。

Redux 和 react-Query 的混合搭配好吗?比如一个网格的页面大小和页码应该放在 redux 中,也许?

完全可以,只要您不将服务器状态同步到 redux。页码和页面大小被认为是“客户端状态”,因为客户端控制着该状态。用户选择页面,服务器根据页面响应数据。我也喜欢在自定义钩子中将其抽象出来:

const useData = () => {
  const pageNumber = useSelector(state => state.pageNumber)
  return useQuery(["data", pageNumber], () => fetchData(pageNumber))
}

这样,您就有了一个可以在任何地方使用的钩子(无需向其传递任何内容),并且如果pageNumber 发生更改,它会自动重新获取数据。

是否可以在某些地方使用纯 axios/fetch 和 redux/react-query 这被认为是一种不受欢迎的做事方式?

如果您不需要为您管理的缓存/加载状态等,那么当然可以。我想到的唯一不想要查询/突变的事情可能是文件下载左右:)

【讨论】:

    【解决方案2】:

    让我们退后一步,看看这些抽象中的每一个帮助我们实现了什么,然后更容易了解应该如何构建应用程序。 很广泛,你有

    1. useQueryuseSwr

    2. Redux 或任何其他全局状态管理工具

    3. concept of lift state up

    4. 上下文接口

    5. 在 url 中保存状态(过滤器说或链接到产品/项目页面)

    useQuery useSwr 负责管理远程状态并提供驻留在远程 API 后面的数据快照。它们有助于获取数据、缓存、错误处理、显示加载微调器。它们为我们提供了额外的功能,例如在某个时间间隔后重新获取或重新获取焦点,在错误时重新获取特定 # 次等。然后我们是否决定在每个组件或父组件中单独调用这些是设计问题,即实现细节.

    Redux 和其他全局状态管理工具有助于在整个客户端应用程序中全局管理本地状态。一个很好的例子就是你的认证用户。这些信息可能在全球范围内都是必需的,所以 redux 听起来是一个拥有这些信息的好地方。购物车是另一个在 redux 商店中可能有意义的例子。

    当您想与兄弟姐妹共享信息时,请提升状态。 This stackoverflow question 是提升状态的完美示例。 DataTableComponent 现在变成了一个受控组件或者你可以称之为展示组件的东西。

    如果提升状态变得太麻烦,那么查看上下文 api 或者可能是 redux。

    因此,以购物车为例,您可能会认为 context api 更有意义,或者提升 state 更有意义,而不是在 redux store 中使用它。我的观点是,没有一种方法可以做到这一点,这将是一个判断电话。

    最后,您可能有一个带有过滤器的页面,您可能希望让您的用户能够发送链接/网址,并且您可能希望收件人看到与发件人相同的信息。所以,现在你必须通过说查询字符串在你的 url 中保存状态。

    回到我上面的评论,没有一种做事的方法。所以,你可能从提升 state 开始,但后来意识到它太麻烦了,所以你可能会切换到 context api 甚至 redux。

    但是这些抽象中的每一个通常确实在您的应用程序中占有一席之地,并且我已经非常成功地结合使用了上述所有抽象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-12
      • 2020-11-01
      • 2013-04-04
      • 1970-01-01
      • 2014-12-26
      • 2021-09-15
      • 2023-03-06
      • 2018-06-21
      相关资源
      最近更新 更多