React useEffect 用于加载数据

IT技术 reactjs
2022-07-26 00:40:44

我正在学习 React Hooks,我想知道在“hook 友好”的同时重新加载数据的最有效方法是什么。

我已经确定了 3 个用例(最新的显然是“更合适的”

使用复制代码

//Example of Using useEffect Hooks by duplicating code
import React, {useState, useEffect} from 'react'
import axios from 'axios'

export default () => {
  const [deals, setDeals] = useState([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    axios({
      method: 'GET',
      url: `http://localhost:1338/deals`
    }).then(res => {
      setDeals(res.data)
      setLoading(false)
    })
  }, [setDeals])
  return(
    <div className="Deals">
      {loading &&
        <p>It's loading</p>
      }
      {!loading &&
        <>
          {deals.map((deal, i) => (
            <div key={i} className="Deal Note">
              {deal.label}
            </div>
          ))}
        </>
      }

      <button onClick={() => {
          setLoading(true)
          axios({
            method: 'GET',
            url: `http://localhost:1338/deals`
          }).then(res => {
            setDeals(res.data)
            setLoading(false)
          }).catch(res => {
            setDeals([{label: 1, label: 2}])
            setLoading(false)
          })
      }}>Fetch Again</button>

    </div>
  )
}

通过在外部函数内部传递 Hooks。代码重用 - 在另一个函数中使用钩子我理解这不是使用钩子的“方式”,尽管这是我的第一个首选解决方案

//Example of Using useEffect Hooks by feeding hooks to external function
import React, {useState, useEffect} from 'react'
import axios from 'axios'

const usefetchMore = (setDeals, setLoading) => {
  console.log("usefetchMore")
  setLoading(true)
  axios({
    method: 'GET',
    url: `http://localhost:1338/deals`
  }).then(res => {
    setDeals(res.data)
    setLoading(false)
  })
}

export default () => {
  const [deals, setDeals] = useState([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    usefetchMore(setDeals, setLoading)
  }, [setDeals])

  return(
    <div className="Deals">
      {loading &&
        <p>It's loading</p>
      }
      {!loading &&
        <>
          {deals.map((deal, i) => (
            <div key={i} className="Deal Note">
              {deal.label}
            </div>
          ))}
        </>
      }

      <button onClick={() => usefetchMore(setDeals, setLoading)}>Fetch Again</button>

    </div>
  )
}

这似乎是“正确的做法”,并且基于useEffect重新触发,因为它正在监听变量的变化,而该reload变量只是为了重新触发它。

//Example of Using useEffect Hooks with variable to re-trigger useEffect
import React, {useState, useEffect} from 'react'
import axios from 'axios'
/* DOESN't WORK */
export default () => {
  const [deals, setDeals] = useState([])
  const [loading, setLoading] = useState(false)
  const [reload, setReload] = useState(0)
  useEffect(() => {
    console.log("Deal4.useEffect")
    setLoading(true)
    axios({
      method: 'GET',
      url: `http://localhost:1338/deals`
    }).then(res => {
      setDeals(res.data)
      setLoading(false)
    })
  }, [setDeals, reload])
  return(
    <div className="Deals">
      {loading &&
        <p>It's loading</p>
      }
      {!loading &&
        <>
          {deals.map((deal, i) => (
            <div key={i} className="Deal Note">
              {deal.label}
            </div>
          ))}
        </>
      }

      <button onClick={() => {
          setReload(reload + 1)
      }}>Fetch Again</button>
    </div>
  )
}

我的问题是:如果我要构建一个显示加载并允许自我刷新的组件,那么使用“React hooks”编写它的正确方法是什么?

1个回答

在 /src/ 中创建一个名为 Photos.js 的组件并给它一个基本列表:

import React from "react";
import { useFetch } from "./hooks";

function Photos() {
  const [data, loading] = useFetch(
    "https://jsonplaceholder.typicode.com/photos?albumId=1"
  );

  return (
    <>
      <h1>Photos</h1>
      {loading ? (
        "Loading..."
      ) : (
        <ul>
          {data.map(({ id, title, url }) => (
            <li key={`photo-${id}`}>
              <img alt={title} src={url} />
            </li>
          ))}
        </ul>
      )}
    </>
  );
}

export default Photos;

现在我们需要一个 Hook!在同一目录中创建一个名为 hooks.js 的文件,并用以下内容填充它:

import { useState, useEffect } from "react";
    
function useFetch(url) {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  
  async function fetchUrl() {
    const response = await fetch(url);
    const json = await response.json();
    setData(json);
    setLoading(false);
  }
 
  useEffect(() => {
    fetchUrl();
  }, []);
 
  return [data, loading];
}

 export { useFetch };

将 Photos 组件导入 App.js 并启动 yarn。完毕!