【问题标题】:Optimizing fetching api data with custom React hooks on searching by keyword change通过关键字更改搜索使用自定义 React 挂钩优化获取 api 数据
【发布时间】:2020-06-19 11:27:17
【问题描述】:

我是 React Hooks 的新手。我编写了一个小代码,向用户显示课程列表。它包含两个主要组件CourseListCourse 以及一个自定义挂钩useCourseList。下面是自定义钩子的代码:

function useCourseList(searchString) {
  const [courses, setCourses] = useState([]);

  useEffect(() => {
    function handleCourseListUpdating(nextCourses) {
      setCourses(nextCourses);
    }

    getCourses(searchString, handleCourseListUpdating)

    return () => {
      setCourses([]);
    }
  }, [searchString]);

  return courses;
}

以上代码是通过getCourses函数通过搜索字符串获取api数据。然后它将检索到的数据更新为由CourseList 组件呈现的courses 状态。 useEffect 函数以 searchString 作为其依赖项触发,以便在搜索字符串更改后不断更新课程数据。

网络浏览器会随着搜索字符串的每个字符变化而刷新多次,尽管这些关键字变化的数据结果是相同的。 例如,我们正在寻找关键字为“游戏”的游戏课程。然后用“G”、“Ga”、“Gam”、“Game”一一调用useEffect 4次。这些关键字与我当前的 api 数据给出了相同的结果,但它们通过 Web 界面不断更新 React DOM。 这会导致浏览器闪烁 4 次,这是不必要的。它还会带来糟糕的用户体验。

是否有任何解决方案可以防止在数据仍然一致时更新 UI?数据流有问题吗?

为了演示,您可以在此处查看完整的示例代码: CodeSandbox

【问题讨论】:

  • useDebounce 钩子可能会有所帮助。
  • 如果我是你,我不会把 () => { setCourses([]); } 作为 useEffect 钩子的清理。你把它放在那里的原因可能是因为你认为它可以给用户一些实例反馈,但 IMO 它实际上可能会导致更多的闪烁。所以我同意@Shubham Khatri 的回答。
  • @Hangindev 酷!我不认为去抖动模式也适用于反应钩子。谢谢你的建议。我试图将它实现到我的演示here。它实际上具有更好的 ui 体验,但浏览器仍然闪烁。您有什么想法可以在纯反应钩子方面使其更流畅吗?
  • @Hangindev 谢谢。我同意你们两个:)

标签: javascript reactjs material-ui react-hooks


【解决方案1】:

您可以进行 2 项更改以获得更好的用户界面体验

  • 为搜索取消 API 调用
  • useEffect 清理中不要将状态设置为空

您可以选择编写自己的自定义 debounce 函数,也可以从 lodash 或 underscore 等库中使用它。完成此操作后,您可以使用useMemo 创建 getCourses 函数的去抖动实例并在 useEffect 中调用它

const debounce = (fn, delay) => {
  let timer = null;
  return function(...args) {
    if (timer){
      clearInterval(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay)
  }
}
// A custom Hook
function useCourseList(searchString) {
  const [courses, setCourses] = useState([]);
  const getDebouncedCourses = useMemo(() => debounce(getCourses, 300), []);
  useEffect(() => {
    function handleCourseListUpdating(courses) {
      setCourses(courses);
    }

    getDebouncedCourses(searchString, handleCourseListUpdating);
  }, [searchString, getDebouncedCourses]);

  return courses;
}

// CourseList component
function CourseList() {
  const [searchString, setSearchString] = useState('');
  const courses = useCourseList(searchString)

  return (
    <div>
      {courses ? (
        <div>
          <TextField style={{ padding: 24 }}
            id="searchInput"
            placeholder="Search for Courses"
            margin="normal"
            onChange={event => setSearchString(event.target.value)}
          />
          <Grid container spacing={4} style={{ padding: 24 }}>
            {courses.map((course, index) => (
              <Grid key={index} item xs={12} sm={6} lg={4} xl={3}>
                <Course course={course} />
              </Grid>
            ))}
          </Grid>
        </div>
      ) : "No courses found"}
    </div>
  );
}

【讨论】:

  • 很高兴有帮助
猜你喜欢
  • 2020-06-20
  • 2022-10-15
  • 2020-04-21
  • 2022-01-07
  • 2020-10-14
  • 2023-01-21
  • 1970-01-01
  • 2014-02-05
  • 1970-01-01
相关资源
最近更新 更多