简体   繁体   中英

Question about queueing state changes with hooks on React

So, I've started studying React by doing class components. There, as far as I understood what I was doing, if I had a

this.state = {
  isLoading: false,
  dataToRender: [],
}

this.setState({ isLoading: true }, async () => {
 const data = await fetchData();
 this.setState({ dataToRender: data , isLoading: false });
})

const message => <p>loading...</p>

if (isLoading) return message();

return (
 dataToRender.map
)

for displaying a "loading" message whenever I call an API for new data, I could know that the setState "queue" would be executed in an order. The outer setState would receive a first state change on the first parameter and a function to execute right after it as the second parameter.

The problem is that I'm having a bit of difficulty wrapping my head around ways to achieve this with hooks. I'm assuming doing

const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);

setLoading(async () => {
  setLoading(true)
  const data = await fetchData()
  setData(data);
  return false;
})

wouldn't work, right? I feel like the overall logic of building this kind of component logic may be different when using hooks somehow... If anyone could at least point me to concept direction it would be nice. Thanks! :)

There's no callback with the dispatch function of useState .

  const fn = async () => {
    setIsLoading(true)
    const data = await fetchData()
    setData(data)
    setIsLoading(false)
  })

The above function is normally invoked upon an event such as onClick or useEffect .

The functions passed as a useState state update function are treated as synchronous functions, so you are effectively saving the implicitly returned Promise object into state.

What you should do is factor the asynchronous logic into a function that is called from an event handler, like onClick , or is called in a component lifecycle, like useEffect .

const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);

const asyncCall = async () => {
  setLoading(true);
  try {
    const data = await fetchData();
    setData(data);
  } catch(error) {
    // handle any errors, logging, etc...
  } finally {
    setLoading(false);
  }
};

This will call/enqueue each state update in the order they are enqueued. You should also surround any asynchronous logic in a try/catch block so you can handle any rejected promises, clear the loading state in a finally so that regardless of resolved/rejected promises, when the code completes it resets the loading state.

depending on Kent React normally batches these calls so you only get a single re-render, but it's unable to do this in an asynchronous callback (like our promise success and error handlers). You can use object for value of useState or use useReducer.

const [state,setState]=useState({isLoading:false,success:false,isError:false,data:[]})

then setting those property on each status.

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