【问题标题】:Reactjs responsively rendering listReactjs 响应式渲染列表
【发布时间】:2023-03-03 17:25:01
【问题描述】:

我正在尝试实现一个响应式搜索栏来过滤纯组件列表(一次最多显示 100 个组件)。但是,在输入首字母和将其显示在搜索栏中以及其下方呈现的组件列表之间存在半秒的冻结。我相信是渲染组件的数量导致了这种延迟,因为将渲染数量限制在 ~20 使得响应几乎是即时的。

我有哪些选择可以最大限度地减少这种延迟并创建几乎即时的渲染?

我看过延迟加载,但我只能找到基于用户滚动动态加载的方法。有没有一种方法可以随着时间的推移拆分列表的呈现,因此不会出现长时间的停顿?

我还查看了React.memo,但延迟是当我从 0 -> 100 个组件开始时,因此在初始加载后缓存并没有真正帮助。有没有办法将这些组件预加载到缓存中?

const SearchPage = ({ dataMap }) => {
  const [searchResults, setSearchResults] = useState([]);

  const onInput = (e) => {
    // near instant response when limit is ~20
    setSearchResults(searchIndex.search(e.target.value, { limit: 100 }));
  };

  return (
    <div>
      <SearchBar onInput={onInput} />
      <DataListTable
        dataList={searchResults.map((dataId) => (dataMap[dataId]))}
      />
    </div>
  );
};


const DataListTable = ({ dataList }) => (
  <table className="table">
    <thead>
      <tr>
        <th>Inputs</th>
        <th>Outputs</th>
        <th>Requirement</th>
      </tr>
    </thead>
    <tbody>
      {dataList.map((data) => (
        <DataRow data={data} key={data.dataId} />
      ))}
    </tbody>
  </table>
);

const DataRow = ({ data }) => {}
export default memo(DataRow);

【问题讨论】:

    标签: javascript reactjs search next.js lazy-loading


    【解决方案1】:

    我可以向您建议几件事,但请记住,我不确定它是否一定会提高组件的性能。

    1. 您的SearchPage 组件被耦合以处理您的searchResults 数据的更新。我认为这可能会导致性能问题,并且从软件设计原则(确切地说是Single-Responsibility principle)来看,它看起来设计得很糟糕。在这种情况下,我会做的是将 state 移动到您的 DataListTable 组件,并将搜索值作为属性传递给它:
    const DataListTable = ({ search }) => {
      const [searchResults, setSearchResults] = useState([]);
    
      useEffect(() => {
        setSearchResults(searchIndex.search(search, { limit: 100 }));
      }, [search]);
    
      return (
        <table className="table">
          <thead>
            <tr>
              <th>Inputs</th>
              <th>Outputs</th>
              <th>Requirement</th>
            </tr>
          </thead>
          <tbody>
            {searchResults.map((data) => (
              <DataRow data={data} key={data.dataId} />
            ))}
          </tbody>
        </table>
      );
    };
    

    那么您的SearchPage 可能如下所示:

    const SearchPage = () => {
      const [search, setSearch] = useState('');
    
      const onInput = (e) => {
        setSearch(e.target.value);
      };
    
      return (
        <div>
          <SearchBar onInput={onInput} />
          <DataListTable search={search} />
        </div>
      );
    };
    
    1. 关于您的dataMap 对象:我认为您应该在从 API 端点收到结果后映射对象。您不应该直接在组件内部进行数据映射。您可以在 searchIndex.search 方法中执行此操作。一个假设的例子是:

    searchService.js

    export const search = async (term, options) => {
      const response = await api.getDataListTableData(term, options);
      const mappedResponse = response.map((x) => ({
        id: x._id,
        name: `${x.first_name} ${x.last_name}`,
      }));
    
      return mappedResponse;
    };
    

    然后只需在您的 DataListTable 组件中调用它:

    import * as searchIndex from './searchService';
    
    useEffect(() => {
      searchIndex.search(search, { limit: 100 }).then((data) => setSearchResults(data));
    }, [search]);
    
    1. 您可以做的另一件事是对搜索结果进行去抖动处理,因为如果不对其进行去抖动处理,可能会导致 2 个缺点:
    • 您的 API 负担着不必要的调用
    • 您的 DataListTable 组件负担着不必要的重新渲染

    为了去抖动,你可以使用这个useDebounce钩子,取自this article

    const useDebounce = (value, timeout) => {
        // Save a local copy of `value` in this state which is local to our hook
        const [state, setState] = useState(value);
    
        useEffect(() => {
            // Set timeout to run after delay
            const handler = setTimeout(() => setState(value), timeout);
    
            // clear the setTimeout listener on unMount
            return () => clearTimeout(handler);
        }, [value, timeout]);
    
        return state;
    };
    

    然后只需在SearchPage 组件中使用useDebounce

    const SearchPage = () => {
      const [search, setSearch] = useState('');
      const debouncedSearchQuery = useDebounce(search, 500);
    
      const onInput = (e) => {
        setSearch(e.target.value);
      };
    
      return (
        <div>
          <SearchBar onInput={onInput} />
          <DataListTable search={debouncedSearchQuery} />
        </div>
      );
    };
    

    我希望其中一些内容会有所帮助。祝你好运!

    【讨论】:

    • 感谢您的回复!我不确定前两个建议,因为它们似乎主要影响代码的样式,但我肯定会实施去抖动建议。
    猜你喜欢
    • 2022-01-26
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    • 2018-11-06
    • 1970-01-01
    • 2018-05-16
    相关资源
    最近更新 更多