功能组件链接多个过滤器并对数组排序

问题描述 投票:0回答:1

我有一个对象数组,这些对象显示在网格中。目标是对数据使用多个过滤器-一个过滤器在特定列中按文本,一个在不同日期范围内,然后按升/降序按各列排序,并且还具有分页功能(我已经为此提供了辅助功能到位)。我的第一种方法是具有多个useEffects,在其中对数据进行过滤/排序并更新状态。问题在于,设置状态的函数显然不会立即更新状态,因此在下一个useEffect中,我不使用由前一个数据过滤的结果,而是对原始数据的过滤。基本上,我需要在原始数组上链接这3种过滤方法,然后进行排序,然后按此顺序分页,但是除非用户更改了设置,否则我不想进行某些过滤/排序。最好的方法来解决此问题的想法。这是一个快速的无效原型。 https://codesandbox.io/s/peaceful-nigh-jysdy用户可以随时更改过滤器,并且所有3个都应生效,我还需要设置一个初始配置来保存初始过滤器值

arrays reactjs react-hooks chaining react-functional-component
1个回答
1
投票

您的代码有2个主要问题:

  1. Reducer在每次调度时都会产生新的过滤后的数组,
  2. 您正在滥用useEffect和useState,并且构建了一个非常复杂的数据流。

让我解释两个问题。

减速器过滤

您在化简器的初始状态下有n个项目。

[
  { id: "124", name: "Michael", dateCreated: "2019-07-07T00:00:00.000Z" },
  { id: "12", name: "Jessica", dateCreated: "2019-08-07T00:00:00.000Z" },
  { id: "53", name: "Olivia", dateCreated: "2019-01-07T00:00:00.000Z" }
]

[当您dispatch一个动作(例如FILTER_BY_TEXT)时,您正在生成一个新的过滤数组:

dispatch({ type: "FILTER_BY_TEXT", payload: { text: 'iv' } });

给予:

[ { id: "53", name: "Olivia", dateCreated: "2019-01-07T00:00:00.000Z" } ]

但是如果您随后分派新值(在这种情况下为ae,因此它应该与Michael匹配:]

dispatch({ type: "FILTER_BY_TEXT", payload: { text: 'ae' } });

您得到一个空数组!

[]

这是因为您要在[[已过滤]]列表上应用ae过滤器!卷积数据流

您的应用程序状态由以下组成:

    您要显示,过滤和排序的数据,
  1. 用户为过滤器和排序选择的当前值。
  2. 对于每个过滤器/分类“ XXX”,您当前的方法使用以下模式:

function reducer(state, action) { switch (action.type) { case 'FILTER_BY_XXX': return filterByXXX(state, action); default: return state; } } function filterByXXX(state, action) { … } function App() { const [state, dispatch] React.useReducer(reducer, []); // (1) Double state “slots” const [xxx, setXXX] = React.useState(INITIAL_XXX); const [inputXXX, setInputXXX] = React.useState(INITIAL_INPUT_XXX); // (2) Synchronization effects (to apply filters) React.useEffect(() => { dispatch({ type: 'FILTER_BY_XXX', payload: xxx }); }, [xxx]); return ( <input value={inputXXX} onChange={event => { // (4) Store the raw input value setInputXXX(event.currentTarget.value); // (5) Store a computed “parsed” input value setXXX((new Date(event.currentTarget.value)); }} /> ); }

让我展示一下谬论:

  1. [(1)不需要双重状态,只是使代码过于复杂。

    对于字符串值,例如filterByTextinputVal,这是很明显的,但是对于“已解析”的值,您需要一点解释。

    确实

    确实

    可以将UI驱动状态与“已解析”状态分开,但是您无需将其存储在状态中!实际上,您始终可以根据实际输入状态重新计算它们。请看一下React文档的这一部分:Main Concepts › Thinking in React › Identify The Minimal (but complete) Representation Of UI State

    “正确的方法是在(1)处移除双槽,并在(5)处移除二传手。然后,您可以

    在渲染时重新计算值

  2. const [inputXXX, setInputXXX] = React.useState(INITIAL_INPUT_XXX); // Here we just recompute a new Date value from the inputXXX state const xxx = new Date(inputXXX); return ( <input value={inputXXX} onChange={event => { setInputXXX(event.currentTarget.value); }} /> );
  1. 您的reducer,如前所述,从完整的数据集开始,并且在每次调度时都进行了[[强制过滤]
。每次调度都指示应用程序在先前应用的过滤器之上添加

another过滤器。之所以会这样,是因为在这种状态下,您只有先前操作的结果。这类似于将长算术运算视为一连串简单运算的方式:

11 + 23 + 560 + 999 = 1593

可以改写为

( ( ( 11 + 23 ) + 560 ) + 999 ) = 1593
( ( (   34    ) + 560 ) + 999 ) = 1593
( (         594       ) + 999 ) = 1593

在每一步上,您失去的都是关于[[how

的信息,但是仍然看到结果了!
[当您的应用程序要“按文本过滤”时,它不想“添加”过滤器,而是将以前的文本过滤器替换为新的文本过滤器。

您通过使“从状态到减速器的状态”与效果同步来对状态变化做出反应。

这的确是useEffect的非常正确的用法,但是如果要同步的值[[from和

    to
都在这种情况下位于相同的位置(或非常靠近),则可能是没有明显的原因使代码过于复杂。
  • 例如,您可以仅在事件处理程序中调度:
  • return <input onChange={event => { dispatch( … ); } />; 但是真正的问题是下一个。

    您将计算结果存储为“状态”,但实际上是“计算值”。您的[[real

    状态是整个数据集,已过滤列表是“将过滤器应用于整个数据集”的产物。

    您需要使自己摆脱对渲染时计算值的恐惧:

      const [inputVal, setInputVal] = React.useState(""); const [selectTimeVal, setSelectTimeVal] = React.useState(""); const [selectSortVal, setSelectSortVal] = React.useState(""); const data = [ {…}, {…}, {…} ]; let displayData = data; displayData = filterByText(displayData, inputVal); displayData = filterByTimeFrame(displayData, selectTimeVal); displayData = sortByField(displayData, selectSortVal); return ( <> <input value={inputVal} onChange={………} /> <select value={selectTimeVal} onChange={………} /> <select value={selectSortVal} onChange={………} /> {displayData.map(data => <p key={data.id}>{data.name}</p>)} </> );
  • 进一步阅读

    一旦您理解了上面列出的主题,您可能希望避免无用的重新计算,但是只有在您实际遇到一些性能问题时才可以! (请参见the very detailed instructions about performance optimizations in the React docs如果您到了这一点,您会发现以下React API和Hooks非常有用:

    React.PureComponent

    React.PureComponent

  • React.Component’s shouldComponentUpdate method

    React.Component

      shouldComponentUpdate
    © www.soinside.com 2019 - 2024. All rights reserved.