как визуализировать контент в компоненте, который загружается с помощью useEffect- React

У меня есть компонент, в который я загружаю данные. Как и ожидалось, сначала отрисовывается компонент, а затем useEffect. Проблема в том, что этот useEffect извлекает данные, которые мне нужно отобразить в моем компоненте. В любом случае, я могу загрузить содержимое компонента после того, как useEffect передаст данные в useState?

import React, { useEffect, useState } from 'react';
import Layout from '../components/global/layout/Layout';
import axios from 'axios';
import { Col, Row } from 'react-bootstrap';
import styles from '../components/page-css/menu.module.css';
import MenuItemHolder from '../components/menu-page/menuItemHolder/menuItemHolder';

const Menu = () => {
    const [ menuItems, setMenuItems ] = useState(false);

    useEffect(() => {
        const fetchData = async () => {
            const result = await axios('https://tahina-test.herokuapp.com/doggos');
            setMenuItems(result.data);
            
        };

        fetchData();
    }, []);

    return (
        <Layout textColor="white">
            <Col>
                <Row className={styles.menuHolder}>
                    <Col className={styles.menu} xs="11" md="8">
                        <h1>Menu</h1>
                        <Row>
                            {menuItems.records.map((item) => (
                                <MenuItemHolder name={item.Name} price={item.UnitPrice} />
                            ))}
                        </Row>
                    </Col>
                </Row>
            </Col>
        </Layout>
    );
};

export default Menu;

person Kisho    schedule 08.07.2020    source источник


Ответы (3)


Насколько я понимаю ваш вопрос, вы спрашиваете, как визуализировать компоненты MenuItemHolder только тогда, когда данные были извлечены, и состояние было заполнено этими данными.

Этого можно добиться двумя способами:

# 1 Инициализируйте menuItems.records пустым массивом:

const [ menuItems, setMenuItems ] = useState({records: []});

так что при первоначальном рендеринге menuItems.records.map([...]) вернет пустой.

# 2 Визуализируйте MenuItemHolder компоненты в соответствии с условием:

<Row>
    {menuItems && menuItems.records.map((item) => (
        <MenuItemHolder name={item.Name} price={item.UnitPrice} />
    ))}
</Row>

Это будет работать, поскольку начальное значение menuItems равно false.

person Befeepilf    schedule 08.07.2020

Вы можете инициализировать menuItems заранее, поэтому доступ к menuItems.records будет действительным.

const Menu = () => {
  const [menuItems, setMenuItems] = useState({ records: [] });

  useEffect(() => {
    //...
    fetchData();
  }, []);

  // records are empty until data fetch
  return (
    <>
      {menuItems.records.map((item) => {
        /*...*/
      })}
    </>
  );
};

export default Menu;

Или просто используйте условный рендеринг:

const Menu = () => {
  const [menuItems, setMenuItems] = useState();

  useEffect(() => {
    //...
    fetchData();
  }, []);

  // Conditional rendering
  return (
    <>
      // Same as menuItems && menuItems.records
      {menuItems?.records.map((item) => {
        /*...*/
      })}
    </>
  );
};

export default Menu;
person Dennis Vash    schedule 08.07.2020

Добавьте состояние loading для визуализации элемента загрузки, пока fetchData получает данные с сервера.

import React, { useEffect, useState } from 'react';
import Layout from '../components/global/layout/Layout';
import axios from 'axios';
import { Col, Row } from 'react-bootstrap';
import styles from '../components/page-css/menu.module.css';
import MenuItemHolder from '../components/menu-page/menuItemHolder/menuItemHolder';

const Menu = () => {
    const [ loading, setLoading ] = useState(false);
    const [ menuItems, setMenuItems ] = useState({records: []});

    const fetchData = async () => {
        setLoading(true);
        const result = await axios('https://tahina-test.herokuapp.com/doggos');
        setLoading(false);
        setMenuItems(result.data);
    };

    useEffect(() => {
        fetchData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    return (
        <Layout textColor="white">
            <Col>
                <Row className={styles.menuHolder}>
                    {loading ? (
                       <Col className={styles.menu} xs="11" md="8">
                            Loading, please wait...
                       </Col>
                    ) : (
                        <Col className={styles.menu} xs="11" md="8">
                            <h1>Menu</h1>
                        
                            {menuItems.records.map((item, index) => (
                                <Row key={index}>
                                    <MenuItemHolder name={item.Name} price={item.UnitPrice} />
                                </Row>
                            ))}

                        </Col>
                    )}
                </Row>
            </Col>
        </Layout>
    );
};

export default Menu;
person glinda93    schedule 08.07.2020