如何让 React Hooks 返回一个数组
Posted
技术标签:
【中文标题】如何让 React Hooks 返回一个数组【英文标题】:How to make React Hooks return an array 【发布时间】:2020-09-29 03:20:20 【问题描述】:我的 React 应用程序中有一些硬编码数据,现在我想从 API 中获取这些数据。我想保留类似数组的格式,因为这就是未来使用数据的方式。
我原来的组件:
import moment from 'moment';
const INITIAL_STATE =
articles:
[
title: 'Guerrilla Public Service Redux (2017)',
tag0: 'story',
points: 421,
created_at: moment('2020-05-27T16:05:32.000Z'),
author: 'DerWOK',
,
title: 'Build Yourself a Redux',
tag0: 'story',
points: 395,
created_at: moment('2020-05-27T16:05:32.000Z'),
author: 'jdeal',
,
],
;
function Articles (state = INITIAL_STATE)
return state;
export default Articles;
这就是我想象的工作方式,但下面的 return() 中应该是什么对我来说是个谜:
import moment from 'moment';
function Articles()
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() =>
fetch("https://hn.algolia.com/api/v1/search?query=redux")
.then(res => res.json())
.then(
(result) =>
setIsLoaded(true);
setItems(result.items);
,
(error) =>
setIsLoaded(true);
setError(error);
)
, [])
if (error)
return <div>Error: error.message</div>;
else if (!isLoaded)
return <div>Loading...</div>;
else
return (
items.map(item => (
???)
);
export default Articles;
编辑:我确实有列表组件来呈现数据。我只需要以可接受的形式返回数据。
【问题讨论】:
这能回答你的问题吗? React.js create loop through Array 你不是想让你的钩子返回一个数组,Fetch
(在你的代码中)是一个功能组件,而不是一个钩子。如果您的问题是???
,那么您只是试图将一个数组呈现为 JSX 元素。请查看建议的副本。
您的result.item
维护着类似数组的结构。如果您正在谈论将数组结构向下传递给孩子,您可以简单地做到这一点 return (<SomeComponent itemList=items />)
而不使用 items.map
但是你在做的不是一个钩子,就像提到的@zero298。您的退货声明与 ???是渲染的返回值,而不是任何其他值。
@habr 所以你的方法是错误的,因为你在其他 if 块上返回 JSX。主要问题是你为什么想要一个钩子来做这个,因为我不确定。如果你能回答这个问题,我们可以帮你创建一个合适的钩子(useGetArticles)
【参考方案1】:
这对我来说看起来不错,除了在最后一个用例和其他用例中没有从组件返回 JSX 之外。试试这个
return (
<ul>
items.map((item, index) => <li key=index>item.title </li> )
</ul>
);
请注意,如果您的项目具有唯一 id,最好使用它们作为键而不是索引。
编辑: 这是一个示例,说明如何在文章中使用挂钩
function useGetArticles()
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() =>
fetch('https://hn.algolia.com/api/v1/search?query=redux')
.then((res) => res.json())
.then(
(result) =>
setIsLoaded(true);
setItems(result.items);
,
(error) =>
setIsLoaded(true);
setError(error);
);
, []);
return [items, isLoaded, error];
function Articles()
const [items, isLoaded, error] = useGetArticles();
if (error)
return <div>Error: error.message</div>;
else if (!isLoaded)
return <div>Loading...</div>;
else
return (
<ul>
items.map((item, index) => (
<li key=index>item.title </li>
))
</ul>
);
【讨论】:
@habr 您的初始代码没有用于反应挂钩的导入。可能也想添加。 我不想返回列表,只返回列表的数据。 @habr 我认为您需要重新考虑在不同情况下返回的内容。在某些情况下返回 JSX 而在其他情况下返回对象数组有点令人困惑。你可以让它工作,但我认为它是不可管理的。对不起,如果我错过了任务的重点 ConnorRobertson 和@dabishan,非常感谢您的时间和帮助。根据您的建议,我决定重新考虑整个事情并决定使用 redux。你可以在这里看到代码:***.com/questions/62503354/…【参考方案2】:如果您要做的只是将 Articles 作为一个函数来维护,那么您必须将其作为一个 Promise(这是多余的,因为 fetch 正在做您需要做的事情)。
您可以按照自己的方式编写自定义钩子,但是 Articles(必须命名为 useArticles
,因为 react 需要它)不能成为您想要的功能,并且您将无缘无故地复杂化。
我的建议是像这样简单地将 useEffect 和其他状态挂钩移动到您的父组件(注意 App
是您的父组件而不是 Articles
):
import React, useState, useEffect from 'react';
const App = () =>
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() =>
Articles()
.then(res =>
setIsLoaded(true);
setItems(res.hits);
setError(false);
)
.catch(error =>
setIsLoaded(true);
setError(true);
)
// you are repeating then/catch again even though you were doing it already on fetch. Only good reason to do this is if you are reusing the api calls in other places.
, [])
return (
<React.Fragment>
Test
<ul>
items.map((item, index) => <li key=index>item.title </li> )
</ul>
</React.Fragment>
);
function Articles()
// too much code just to hide it inside a function
return new Promise((resolve, reject) =>
fetch("https://hn.algolia.com/api/v1/search?query=redux")
.then(res => resolve(res.json()))
.catch(error => reject(error))
);
export default App;
这是重新格式化代码的钩子方法。但这本身并不意味着它更好:
import React, useState, useEffect from 'react';
const App = () =>
// getting all useful state from the hook
const error, isLoaded, items, fetchItems = useGetArticles();
useEffect(() =>
fetchItems(); // calling the method that ask for new data and loads item in the hook's state
)
return (
<React.Fragment>
<ul>
items.map((item, index) => <li key=index>item.title </li> )
</ul>
</React.Fragment>
);
const useGetArticles = () =>
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
const fetchItems = () =>
fetch("https://hn.algolia.com/api/v1/search?query=redux")
.then(res => res.json())
.then(res =>
setIsLoaded(true);
setItems(res.hits);
setError(false);
)
.catch(error =>
setIsLoaded(true);
setError(true);
)
;
// only return useful states and functions that main component can use
return error, isLoaded, items, fetchItems
export default App;
【讨论】:
非常感谢@dabishan。我想要么我设法在这里返回数组,要么需要使用 Redux。第一个选项听起来更简单。如果它不打扰你,如果你能添加钩子版本,我将不胜感激。以上是关于如何让 React Hooks 返回一个数组的主要内容,如果未能解决你的问题,请参考以下文章
如何更改数组状态容器中的对象属性? React Hooks 使用状态
React Hooks --- useState 和 useEffect