简体   繁体   中英

ReactJS - how to fetch multiple data with useEffect

I'm fairly new to react, right now I have a function that is fetching some data in my useEffect hook, using a loading state to manage component rendering and then loading my state component with that data, everything is working fine.

But now I have to implement another function to fetch some other data.

How can this be implemented in the best way possible? Do I need to create another useEffect for another fetch function?

Here is my code:

export default function Home() {
  const [ageOptions, setAgeOptions] = useState([])
  const [age, setAge] = useState('')
  const [loading, setLoading] = useState(false)

  // get age option from API
   useEffect(() => {
    setLoading(true)
    const fetchAgeOptions = () => {
     // transform the data to load properly in my react-select component
      function transform(data) {
        const options = data.map(function (row) {
          return { value: row.id, label: row.description, startAge: row.startAge, endAge: row.endAge }
        })
        setAgeOptions(options)
        setLoading(false)
      }
      api.get('someurl.com').then(response =>
        Object.values(response.data.rows)).then(data => transform(data))
    }
    fetchAgeOptions()
  }, [])


  return loading ? <div>Loading...</div> :
    <>
      <label>Age level</label>
      <Select
        value={age}
        options={ageOptions}
        placeholder="All"
        onChange={val => {
          setAge(val)
        }}
      />
    </>
}

Your current useEffect will only run on mount (because you added the empty brackets at the end of the use effect []). If you are planning on only calling this function one time (on mount) then you can put it in the same useEffect. If you want to call a function every time the state of something updates then all you have to do is make a separate useEffect with the state as a dependency.

useEffect(() => {

  }, ['variable-here-on-update-will-call-whatever-is-in-the-useEffect'])

Here is an example on mine:

//will run on componentDidMount
useEffect(() => {
  setError(false);
}, []);

//will run if error is updated in parent component
useEffect(() => {
  if (error && error.body) {
    setError(true);
  }
}, [error]);

I would also recommend taking out your 'fetchAgeOptions' function from the useEffect (and add it above) as you are calling to it anyways. This way it is not a private function to the useEffect and it will look cleaner.

您可能想要创建一个名为 useFetch 的自定义钩子,其中包含 useEffect 和 useState,它应该返回状态(初始、加载、错误和成功)和结果,然后仅当第一个效果具有正确的状态时才调用第二个效果。

Just like you can use the State Hook more than once, you can also use several effects. This lets us separate unrelated logic into different effects:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}

Hooks let us split the code based on what it is doing rather than a lifecycle method name. React will apply every effect used by the component, in the order they were specified.

React Docs - Effect Hook https://reactjs.org/docs/hooks-effect.html

Use a promise all


   useEffect(() => {
    setLoading(true)
    const fetchAgeOptions = () => {
     // transform the data to load properly in my react-select component
      function transform(data) {
        const options = data.map(function (row) {
          return { value: row.id, label: row.description, startAge: row.startAge, endAge: row.endAge }
        })
        setAgeOptions(options)
        setLoading(false)
      }
      api.get('someurl.com').then(response =>
        Object.values(response.data.rows)).then(data => transform(data))
    }
  const fetchAgeOptions = () => {
     // transform the data to load properly in my react-select component
      function transform(data) {
        const options = data.map(function (row) {
          return { value: row.id, label: row.description, startAge: row.startAge, endAge: row.endAge }
        })
        setAgeOptions(options)
        setLoading(false)
      }
      api.get('someurl.com').then(response =>
        Object.values(response.data.rows)).then(data => transform(data))
    }
    const fetchAgeOptions = () => {
     // transform the data to load properly in my react-select component
      function transform(data) {
        const options = data.map(function (row) {
          return { value: row.id, label: row.description, startAge: row.startAge, endAge: row.endAge }
        })
        setAgeOptions(options)
        setLoading(false)
      }
      api.get('someurl.com').then(response =>
        Object.values(response.data.rows)).then(data => transform(data))
    }

  Promise.all([fetchMethod1,fetchMethod2,fetchMethod3]).then(data=>{
// DATA IS AN ARRAY AND THEY ARE IN ORDER AS PLACED IN 
})
    
  }, [])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM