如何在useEffect-React加载的组件中渲染内容
how to render content in the component that is loaded by 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;
您可以预先初始化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;
或者只使用 conditional rendering:
const Menu = () => {
const [menuItems, setMenuItems] = useState();
useEffect(() => {
//...
fetchData();
}, []);
// Conditional rendering
return (
<>
// Same as menuItems && menuItems.records
{menuItems?.records.map((item) => {
/*...*/
})}
</>
);
};
export default Menu;
添加 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;
据我了解你的问题,你问的是如何仅在获取数据并且已使用此数据填充状态时呈现 MenuItemHolder
组件。
有两种方法可以实现:
#1 用空数组初始化 menuItems.records
:
const [ menuItems, setMenuItems ] = useState({records: []});
这样在初始渲染时,menuItems.records.map([...])
将 return 为空。
#2 根据条件渲染 MenuItemHolder
组件:
<Row>
{menuItems && menuItems.records.map((item) => (
<MenuItemHolder name={item.Name} price={item.UnitPrice} />
))}
</Row>
这将起作用,因为 menuItems
的初始值是 false
。
我有一个要向其中获取数据的组件。正如预期的那样,组件首先呈现,然后是 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;
您可以预先初始化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;
或者只使用 conditional rendering:
const Menu = () => {
const [menuItems, setMenuItems] = useState();
useEffect(() => {
//...
fetchData();
}, []);
// Conditional rendering
return (
<>
// Same as menuItems && menuItems.records
{menuItems?.records.map((item) => {
/*...*/
})}
</>
);
};
export default Menu;
添加 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;
据我了解你的问题,你问的是如何仅在获取数据并且已使用此数据填充状态时呈现 MenuItemHolder
组件。
有两种方法可以实现:
#1 用空数组初始化 menuItems.records
:
const [ menuItems, setMenuItems ] = useState({records: []});
这样在初始渲染时,menuItems.records.map([...])
将 return 为空。
#2 根据条件渲染 MenuItemHolder
组件:
<Row>
{menuItems && menuItems.records.map((item) => (
<MenuItemHolder name={item.Name} price={item.UnitPrice} />
))}
</Row>
这将起作用,因为 menuItems
的初始值是 false
。