skip to Main Content

I’m learning React and can’t understand how to properly use async functions inside of the components

I want to create a test component that:

  • Receives a list of requests to be sent
  • Executes them one by one (in async function)
  • When the response is received, it appends it to the list of responses
  • If all requests were successful automatically shows a modal
  • If any request fails, shows a button that the user needs to click in order to show modal

Right now I managed to do this

function requestReportReducer(state, action) {
    switch (action.type) {
        case 'append':
            return [...state, action.payload]
    }
}

export default function RequestList(props) {
    const [report, reduceReport] = useReducer(requestReportReducer, [])
    const [hasErrors, setHasErrors] = useState(false)

    useEffect(() => {
        async function sendRequests() {
            for (const requestData of Object.values(props.requests)) {
                const response = await sendRequest()
                const isSuccessful = response.statusCode < 400

                reduceReport({
                    type: 'append', payload: {
                        isSuccessful: isSuccessful,
                        responseCode: response.statusCode,
                        responseBody: response.body,
                    }
                })

                if (!isSuccessful)
                    setHasErrors(true)
            }

            if (!hasErrors)
                showAllRequestsAreSentModal()
        }

        sendRequests()
    }, [])

    return (
        <div>
          <dl>
            {report && report.map((requestReport: RequestReport) => (
              <p>some html here</p>
            ))}
          </dl>
          {hasErrors && <button onClick={showAllRequestsAreSentModal}>Finish execution</button>}
        </div>
    )
}

As you can see, I want to be able to set hasErrors var and read it in both the async function and JSX which does not seem to work. I understand that this implementation is incorrect, but how can I fix it? I have found a lot of similar questions, but could not understand how to apply the suggestions proposed there in my case.

3

Answers


  1. When you call setHasErrors(true) inside the loop, it will not immediately update hasErrors. You can use the useEffect hook to watch for changes in hasErrors and trigger the modal accordingly.

    export default function RequestList(props) {
        const [report, reduceReport] = useReducer(requestReportReducer, []);
        const [hasErrors, setHasErrors] = useState(false);
    
        useEffect(() => {
            async function sendRequests() {
                for (const requestData of Object.values(props.requests)) {
                    const response = await sendRequest();
                    const isSuccessful = response.statusCode < 400;
    
                    reduceReport({
                        type: 'append', payload: {
                            isSuccessful: isSuccessful,
                            responseCode: response.statusCode,
                            responseBody: response.body,
                        }
                    });
    
                    if (!isSuccessful) {
                        setHasErrors(true);
                    }
                }
            }
    
            sendRequests();
        }, []);
    
        useEffect(() => {
            if (!hasErrors) {
                showAllRequestsAreSentModal();
            }
        }, [hasErrors]);
    
        const showAllRequestsAreSentModal = () => {
            // Show your modal here
        }
    
        return (
            <div>
              <dl>
                {report && report.map((requestReport: RequestReport) => (
                  <p>some html here</p>
                ))}
              </dl>
              {hasErrors && <button onClick={showAllRequestsAreSentModal}>Finish execution</button>}
            </div>
        )
    }
    
    Login or Signup to reply.
  2. If you’re just learning react, it’s fine to code stuff like this yourself.

    For real-work projects, I highly recommend using a wrapper around Promises.

    @tanstack/react-query is my personal (an many other’s) go-to solution.

    Login or Signup to reply.
  3. You’re facing this issue because it doesn’t immediately update the hasErrors variable in the outer scope , for solving this issue you can use the useEffect dependency array and update hasErrors using setHasErrors within the useEffect.

    useEffect(() => {
        async function sendRequests() {
          for (const requestData of Object.values(props.requests)) {
            const response = await sendRequest();
            const isSuccessful = response.statusCode < 400;
    
            reduceReport({
              type: 'append',
              payload: {
                isSuccessful: isSuccessful,
                responseCode: response.statusCode,
                responseBody: response.body,
              }
            });
    
            if (!isSuccessful) {
              setHasErrors(true);
            }
          }
        }
    
        sendRequests().then(() => {
          if (!hasErrors) {
            showAllRequestsAreSentModal();
          }
        });
    
        // Include 'hasErrors' in the dependency array to monitor its changes
      }, [hasErrors]);
    
     }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search