使用多个 React useState() 挂钩从 json api 获取类别标题和帖子

Use multiple React useState() hooks to fetch Category title and posts from json api

我正在使用 React useState() 和 useEffect 从 api (mock-data/my-data.json).

中获取多个数据

从 api 我想获取 类别标题 帖子列表 并在 jsx.

这是使用 useState()useEffect() 获取数据的正确方法吗?我制作了多个 useState 常量,所以在我可以在渲染方法中渲染 Title 和列表操作 Posts 之后:

function ArticleList() {
  const [categoryTitle, setCategoryTitle] = useState('')
  const [posts, setPosts] = useState([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    axios
      .get('mock-data/my-data.json')
      .then(res => {
        console.log(res.data)
        setCategoryTitle(res.data['title'])
        setPosts(res.data.allItems)
        setLoading(false)
      })
      .catch(err => {
        console.log(err)
      })
  }, [])

  if (loading) {
    return <p>Loading articles...</p>
  }

  return (
    <div>
      <h1>{categoryTitle}</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.titel}</li>
        ))}
      </ul>
    </div>
  )
}

是的,这是正确的方法。如果你只想使用一个 useState,你可以克隆状态对象。 例如:

const [state, setState] = useState({
  title: "",
  posts: []
});

// For Title
setState({...state, title: "New Title"})

// For Posts
setState({...state, posts: [{...post...}]}

但我想使用 lodash 克隆、immer 库或类似的东西。

我觉得不错。

如果我要重构此代码,我更愿意使用 async/await,并且我喜欢使用状态枚举而不是布尔值,用于 loading/loaded/error 个状态。

function ArticleList() {
  const [categoryTitle, setCategoryTitle] = useState('');
  const [posts, setPosts] = useState([]);
  const [state, setState] = useState('loading');

  useEffect(() => {
    const fetchPosts = async () => {
      setState('loading');

      let response = axios.get('mock-data/my-data.json');

      try {
        response = await response;
      } catch (error) {
        setState('error');
        return;
      }

      setCategoryTitle(response.data['title']);
      setPosts(response.data.allItems);
      setState('loaded');
    };

    fetchPosts();
  }, []);

  if (state === 'loading') {
    return <p>Loading articles...</p>;
  }

  if (state === 'error') {
    return <p>Error loading articles...</p>;
  }

  return (
    <div>
      <h1>{categoryTitle}</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.titel}</li>
        ))}
      </ul>
    </div>
  );
}

差不多就这些了,我唯一强烈推荐的是使用 await 而不是著名的 hadoukens/pyramids of doom,所以一个简单的代码是:

function ArticleList() {
  const [categoryTitle, setCategoryTitle] = useState('')
  const [posts, setPosts] = useState([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    async function getData(){
    try{
        setLoading(true)
        res = await axios.get('mock-data/my-data.json');    
        console.log(res.data)
        setCategoryTitle(res.data['title'])
        setPosts(res.data.allItems)
        setLoading(false)        
    }catch(err){
        console.log(err)
      }
    }
    getData();
    }, [])

  if (loading) {
    return <p>Loading articles...</p>
  }

  return (
    <div>
      <h1>{categoryTitle}</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.titel}</li>
        ))}
      </ul>
    </div>
  )
}

如果您想同时设置多个状态,通常使用 useReducer 钩子而不是使用多个 useState 钩子是个好主意。您的示例是您尝试将多个状态设置在一起的情况。 useReducer 使用 reducer 函数,其中可以操纵合并状态。在我看来,这使代码更具凝聚力和可读性。 请参阅下面的示例代码。为简单起见,我删除了 axios,但你应该明白了。

https://codesandbox.io/s/bold-platform-hv6pi?file=/src/ArticleList.js