Реагируйте: не показывайте модальный режим, пока все содержимое не будет правильно загружено

#reactjs

Вопрос:

Я создал статический веб-сайт React и разместил его на страницах Github.

Как вы можете видеть, всякий раз, когда вы нажимаете на фильм или сериал, появляется модал с постером фильма/телевизора(загруженным из API OMDb) и некоторыми метаданными. Проблема в том, что контент загружается слишком медленно. Требуется секунда(иногда больше), прежде чем появится содержимое.

Я понимаю, что не могу ожидать, что он загрузится намного быстрее, но я бы хотел вообще не показывать модал, пока все не будет выглядеть хорошо(т. Е. Идеально загружено). Возможно, благодаря появлению «Загрузка..», пока мы ждем. Это не должно быть чем-то необычным, так как оно будет отображаться на экране не более 1-2 секунд.

У вас есть какие-нибудь советы для новичка в React?

Соответствующий код:

 function ImdbInfo(props) {
    const [data, setData] = useState({ imdbData: [] });
 
    useEffect(() => {
        const imdbId = getImdbId(props.url);

        const fetchData = async () => {
            const result = await axios(
                `https://www.omdbapi.com/?i=${imdbId}amp;apiKey=${apiKey}`,
            );
            setData(result.data);
        };
        fetchData();
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    return (
        <div className="modal-content">
            <div className="metadata" onClick={props.handleClose}>
                <h1 className="modal-header">{data.Title}</h1>
                <img className="modal-poster" src={data.Poster} alt="poster" />
                <p className="modal-info">{getDirectorOrWriter(data)}</p>
                <p className="modal-info">IMDb Rating: {getImdbScore(data.Ratings)}</p>
            </div>
            {createImdbLink(props.url)}
        </div>
    );
}

 

И:

 const MediaModal = ({ handleClose, show, data }) => {
    const showHideClassName = show ? 'modal display-block' : 'modal display-none';
    const imdbData = show ? <ImdbInfo url={data.imdbLink} handleClose={handleClose} /> : <div />;
  
    return (
      <div className={showHideClassName} onClick={handleClose}>
        <section className='modal-main'>
            {imdbData}
        </section>
      </div>
    );
};

export default MediaModal;
 

Ответ №1:

Установите loading значение true перед вызовом api и установите loading false значение после того, как api вернет успех/сбой.

Проверьте обновленный код ниже

   function ImdbInfo(props) {
    const [data, setData] = useState({ imdbData: [] });
    const [loading, setLoading] = useState(false);

    useEffect(() => {
      const imdbId = getImdbId(props.url);

      const fetchData = async () => {
        setLoading(true);
        try {
          const result = await axios(
            `https://www.omdbapi.com/?i=${imdbId}amp;apiKey=${apiKey}`
          );
          setData(result.data);
          setLoading(false);
        } catch (err) {
          setLoading(false);
        }
      };
      fetchData();
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    return (
      <div>
        {loading ? (
          <div>Loading...</div>
        ) : (
          <div className="modal-content">
            <div className="metadata" onClick={props.handleClose}>
              <h1 className="modal-header">{data.Title}</h1>
              <img className="modal-poster" src={data.Poster} alt="poster" />
              <p className="modal-info">{getDirectorOrWriter(data)}</p>
              <p className="modal-info">
                IMDb Rating: {getImdbScore(data.Ratings)}
              </p>
            </div>
            {createImdbLink(props.url)}
          </div>
        )}
      </div>
    );
  }
 

Ответ №2:

Если я правильно понимаю ваш код, вы создаете MediaModal компонент с дочерним компонентом ImdbInfo , в котором вы получаете некоторые данные. Я предполагаю, что у этого MediaModal есть родительский компонент, в котором вы переключаетесь и используете свой модальный: вы не предоставили код, но давайте назовем его MainComponent

Вместо того, чтобы извлекать данные внутри ImdbInfo , вы могли бы извлечь их MainComponent и передать результат в качестве реквизита:

  • Внутри основного компонента:
 // Onclick to toggle modal:
// - fetch data just like you did in ImdbInfo
// - then set show=true
// Then use your modal
<MediaModal handleClose={plop} show={plip} infos={fetchedData} url={imdbLink} />
 
  • Медиамодальный:
 const MediaModal = ({ handleClose, show, infos, url}) => {
    const showHideClassName = show ? 'modal display-block' : 'modal display-none';
    const imdbData = show ? <ImdbInfo infos={infos} url={url} handleClose={handleClose} /> : <div />;
  
    return (
      <div className={showHideClassName} onClick={handleClose}>
        <section className='modal-main'>
            {imdbData}
        </section>
      </div>
    );
};

export default MediaModal;
 
  • ImdbInfo:
 function ImdbInfo({infos, handleClose}) {
    return (
        <div className="modal-content">
            <div className="metadata" onClick={handleClose}>
                <h1 className="modal-header">{infos.Title}</h1>
                <img className="modal-poster" src={infos.Poster} alt="poster" />
                <p className="modal-info">{getDirectorOrWriter(infos)}</p>
                <p className="modal-info">IMDb Rating: {getImdbScore(infos.Ratings)}</p>
            </div>
            {createImdbLink(url)}
        </div>
    );
}