如何让 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 (&lt;SomeComponent itemList=items /&gt;) 而不使用 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

Apollo react hooks 数组对象突变

react native - 如何在元组数组中使用 React Hooks?

手把手教你React Hooks

React Hooks - 我如何实现 shouldComponentUpdate?