【问题标题】:Proper way to render content without flickering ? React + Redux + TS呈现内容而不闪烁的正确方法?反应 + 还原 + TS
【发布时间】:2021-08-25 18:42:10
【问题描述】:

您能帮我了解渲染内容的逻辑吗? 我正在使用 React、Redux、TS 进行宠物项目,并且在页面加载时出现内容渲染问题。

其实有两个问题。

第一个问题:

  1. 当我点击一张卡片时,发送卡片数据的 GET 请求。
  2. 卡片页面已打开(使用 useParams 进行动态路由)
  3. 当从服务器接收到数据时,它会发送到 Redux State
  4. 页面呈现正常(因为初始状态为空)。

然后我点击另一张卡片,问题就出在这里: 5) 我点击另一张卡片并发送新日期的 GET 请求。 6)此时状态存储了之前的卡片数据并渲染它 7)新数据来自服务器和渲染。 8) 在很短的时间内,我看到以前的卡片数据......它在闪​​烁。如下图

我的问题是:我应该在点击卡片时将卡片状态重置为初始状态(空状态)吗?或者应该有另一种方法来做到这一点?

第二个问题: 为了解决第一个问题,我添加了 onClick 函数,它将卡片状态重置为其初始状态:

const initialState: IMovieState = {
  movie: {
    filmId: 0,
    nameRu: '',
    nameEn: '',
    webUrl: '',
    posterUrl: '',
    year: 0,
    filmLength: '',
    slogan: '',
    description: '',
    type: '',
    countries: [],
    genres: [],
    rating: {
      rating: 0,
      ratingVoteCount: 0,
      ratingImdb: 0,
      ratingImdbVoteCount: 0,
    },
    images: {
      posters: [],
    },
  },
  isLoading: false,
  movieError: null,
};

这似乎解决了问题 1,但还有另一个...在页面加载有黄色按钮和图像的 alt 数据(无法加载)在左上角可见。下图。

我的问题是:我应该添加一个条件:如果对象键(无论是什么键)有数据然后渲染它还是应该在状态中添加一个新键,例如 isData: false/true条件是如果 data=true 然后渲染它。

MoviePage.tsx

interface IMovieProps {
  filmId: string;
}

const MoviePage: React.FC = () => {
  const { filmId } = useParams<IMovieProps>();
  const dispatch = useDispatch();
  const { isLoading, movie, movieError } = useTypedSelector((state) => state.singleMovie);
  const { nameRu, nameEn, description, posterUrl, year, genres, filmLength } = movie;
  
  useEffect(() => {
    dispatch(fetchMovie(filmId));
  }, [filmId, dispatch]);


  return (
    <section className={styles.section}>

      <div className={styles.backgroundImage} style={{ backgroundImage: `url(${posterUrl})` }} />

      {isLoading && <Preloader />}

      {!isLoading && !!movieError && <Message message={movieError} />}

      {!isLoading && !movieError && (
        <>
          <GoBackLink text={'Назад'} />

          <div className={styles.content}>
            <img src={posterUrl} alt='Постер' className={styles.poster} />
            <div>
              <h1 className={styles.title}>{nameRu}</h1>
              <h2 className={styles.subtitle}>
                {nameEn && `${nameEn}, `}
                <span>{year}</span>
              </h2>
              {filmLength && <p className={styles.subtitle}>Продолжительность: {filmLength} ч</p>}

              <ul className={styles.genresList}>
                {genres.map(({ genre }, idx) => (
                  <Genres genre={genre} key={idx} />
                ))}
              </ul>

              {description && (
                <>
                  <h3 className={styles.heading}>Описание</h3>
                  <p className={styles.text}>{description}</p>
                </>
              )}
            </div>
          </div>
        </>
      )}
    </section>
  );
};

export default MoviePage;

点击时卡片的状态:

【问题讨论】:

  • 点击卡片时,你会做什么?您是否正在移动到不同的页面并进行 API 调用以获取所选卡的附加信息?还是您将所选卡信息设置为状态?
  • 点击卡片时,我发送 GET 请求以获取卡片数据。同时我使用 useParams 移动到卡片页面
  • 您可以为您的卡片页面添加代码吗?
  • 第一个问题的答案是“是的,当你点击另一张卡片时重置 redux 中的状态是一个合乎逻辑的操作过程”,只要记住重置如果您点击同一张卡片(例如,通过检查操作有效负载中的卡片 ID 与该状态中的卡片 ID 不同),则显示状态。对于第二个问题,这是因为您尝试在 GET 请求返回任何值之前加载一些图像;您可以通过使用条件渲染来解决这个问题(仅在卡片状态不为空或未定义时渲染图像)
  • @secan 因为我使用 redux 和 TS ...描述了初始状态。因此,当我第一次单击卡片时 - 它是带有许多空道具的对象......所以我可以添加条件 null ||不明确的。我添加了第一次点击卡片的屏幕截图

标签: javascript reactjs


【解决方案1】:

我喜欢做的是我喜欢在 useState() 中使用条件以及检查特定键是否有数据。我不会在每次点击之前重置状态。相反,我检查特定的 post 键是否已经存在处于 redux 状态的数据。如果该特定键有数据,那么我只使用该数据,并且不会在每次呈现相同组件时都发出获取请求。如果它没有数据,那么我提出请求。

1- 检查项目键是否已经存在数据。如果它不需要进行获取请求,则使用数据来渲染组件。
2- 将数据连接到 redux 存储。不要覆盖状态。
3-以对象的形式存储数据。其中键将是项目的唯一键。这样您可以检查密钥是否存在(例如:data[key]?.length > 0)


希望对您有所帮助。

// example
  
  const [loading, setLoading] = useState(false);
  const data = useSelector(getItemData) // here getItemData is a seletor from reselect library 
  const dispatch = useDispatch();
  
  
  const hasData = Boolean(data.length)
  useEffect(() => {
    if (hasData) return;
    const fetchData = async () => {
      setLoading(true);
      await dispatch(fetchItems()); // make fetchItems redux thunk async as well
      setLoading(false)
    }

    fetchData()
  }, [condition]);


  if (loading) return <div>Loading ...</div>
  
  return <MyComponent />

【讨论】:

    猜你喜欢
    • 2019-09-16
    • 1970-01-01
    • 2014-04-29
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多