首页 > 解决方案 > 在事件处理程序中从 localStorage 获取数据时不呈现组件

问题描述

在事件处理程序中,当从状态变量获取数据localStorage并将此数据分配给状态变量时,不会重新渲染组件以反映新值

逻辑是验证localStorage是否存在且当前id有数据,然后从localStorage给状态变量赋值,否则从endpoints获取数据并同步localStorage

如果满足这些条件,我会从 localStorage 获取数据并将值分配给状态变量,但组件不会重新渲染

if (hasLocalStorage() && existInLocalStorage(id)) {
  const [show, episodes, cast] = fetchFromLocalStorage(id);

  setShow(show);
  setEpisodes(episodes);
  setCast(cast);

  return false;
}

这是完整的功能

function clickHandler(id) {
  setIsSummaryLoading(true);
  setHasSummaryLoadingErrors(false);

  if (hasLocalStorage() && existInLocalStorage(id)) {
    const [show, episodes, cast] = fetchFromLocalStorage(id);

    setShow(show);
    setEpisodes(episodes);
    setCast(cast);

    return false;
  }

  const endpoints = [
    `/shows/${id}`,
    `/shows/${id}/episodes`,
    `/shows/${id}/cast`,
  ];

  const promises = endpoints.map((endpoint) => fetcher(endpoint));

  Promise.all(promises)
    .then((data) => {
      const [show, episodes, cast] = data;

      setIsSummaryLoading(false);

      syncLocalStorage({ id, data });

      setShow(show);
      setEpisodes(episodes);
      setCast(cast);
    })
    .catch((error) => {
      setHasSummaryLoadingErrors(true);
      setIsSummaryLoading(false);

      console.error(error.message);
    });
}

其他相关功能如下

function syncLocalStorage({ id, data }) {
  let storage = localStorage.maze ? JSON.parse(localStorage.maze) : {};

  storage[id] = data;

  localStorage.maze = JSON.stringify(storage);
}

function fetchFromLocalStorage(id) {
  return JSON.parse(localStorage.maze)[id];
}

function hasLocalStorage() {
  return localStorage.maze !== undefined;
}

function existInLocalStorage(id) {
  return id in JSON.parse(localStorage.maze);
}

这是完整的组件代码

function App() {
  const [show, setShow] = useState({});
  const [episodes, setEpisodes] = useState([]);
  const [cast, setCast] = useState(null);
  const [shows, setShows] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [hasErrors, setHasErrors] = useState(false);
  const [isSummaryLoading, setIsSummaryLoading] = useState(false);
  const [hasSummaryLoadingErrors, setHasSummaryLoadingErrors] = useState(false);

  function submitHandler(query) {
    setIsLoading(true);
    setHasErrors(false);

    fetcher(`/search/shows?q=${query}`)
      .then((shows) => {
        const showList = shows.map((entry) => entry.show);

        setIsLoading(false);

        setShows(showList);
      })
      .catch((error) => {
        setHasErrors(true);
        setIsLoading(false);

        console.error(error.message);
      });
  }

  function clickHandler(id) {
    setIsSummaryLoading(true);
    setHasSummaryLoadingErrors(false);

    if (hasLocalStorage() && existInLocalStorage(id)) {
      const [show, episodes, cast] = fetchFromLocalStorage(id);

      setShow(show);
      setEpisodes(episodes);
      setCast(cast);

      return false;
    }

    const endpoints = [
      `/shows/${id}`,
      `/shows/${id}/episodes`,
      `/shows/${id}/cast`,
    ];

    const promises = endpoints.map((endpoint) => fetcher(endpoint));

    Promise.all(promises)
      .then((data) => {
        const [show, episodes, cast] = data;

        setIsSummaryLoading(false);

        syncLocalStorage({ id, data });

        setShow(show);
        setEpisodes(episodes);
        setCast(cast);
      })
      .catch((error) => {
        setHasSummaryLoadingErrors(true);
        setIsSummaryLoading(false);

        console.error(error.message);
      });
  }

  return (
    <>
      <div>
        <Form onSubmit={submitHandler} />
        {hasErrors ? <HasErrors /> : null}
        {isLoading ? (
          <IsLoading />
        ) : (
          <Shows shows={shows} onClick={clickHandler} />
        )}
      </div>
      <ShowDetail
        show={show}
        isSummaryLoading={isSummaryLoading}
        hasSummaryLoadingErrors={hasSummaryLoadingErrors}
      />
      <ShowSummary
        episodes={episodes}
        cast={cast}
        isSummaryLoading={isSummaryLoading}
        hasSummaryLoadingErrors={hasSummaryLoadingErrors}
      />
    </>
  );
}

感谢您的意见

标签: javascriptreactjs

解决方案


设置setIsSummaryLoading状态变量false解决问题

if (hasLocalStorage() && existInLocalStorage(id)) {
  const [show, episodes, cast] = fetchFromLocalStorage(id);

  setShow(show);
  setEpisodes(episodes);
  setCast(cast);
  setIsSummaryLoading(false); // set to false

  return false;
}

原因是组件ShowDetailShowSummary接收isSummaryLoadingas 属性的值,并且它的值保持不变true

<ShowDetail
  show={show}
  isSummaryLoading={isSummaryLoading}
  hasSummaryLoadingErrors={hasSummaryLoadingErrors}
/>
<ShowSummary
  episodes={episodes}
  cast={cast}
  isSummaryLoading={isSummaryLoading}
  hasSummaryLoadingErrors={hasSummaryLoadingErrors}
/>

这是 ShowDetail 组件的代码,因为isSummaryLoading被设置为true<IsLoading />被渲染

function ShowDetail({ show, isSummaryLoading, hasSummaryLoadingErrors }) {
  return (
    <div>
      {hasSummaryLoadingErrors ? <HasErrors /> : null}
      {isSummaryLoading ? (
        <IsLoading />
      ) : (
        <>
          {Object.keys(show).length > 0 && (
            <>
              <h1>{show.name}</h1>
              <img src={show.image && show.image.medium} alt={show.name} />
              <p dangerouslySetInnerHTML={createMarkup(show.summary)} />
              <ShowTable show={show} />
            </>
          )}
        </>
      )}
    </div>
  );
}

感谢评论的人


推荐阅读