Fetching and Posting Data in React


This video is part of the following playlists:


Learn how to make network requests in a react app to fetch data on load, and post data when users submit a form.

Join this channel to get access to perks: https://www.youtube.com/channel/UC6aTLuI_j4-0wiDSzmaPctQ/join

This is video #10 in my react series:

React Proxy | Easiest Fix to CORS Errors: https://youtu.be/N4yUiQiTvwU

Chapters:

  • 0:00​ Intro
  • 1:05 Fetch Data in useEffect
  • 4:40 Error State
  • 7:37 Loading State
  • 9:55 Custom Hook
  • 12:26 Suspense
  • 13:49 Implementing Search
  • 15:23 Race Condition
  • 17:05 Abort Controller
  • 19:22 Posting Form Data
  • 22:44 Sharing State
  • 27:54 Summary

code

App.jsx

import { useState } from 'react'
import axios from 'axios'
import './App.css'
import { useEffect } from 'react'
import NewJokeForm from './NewJokeForm'


function App() {
  const [jokes, setJokes] = useState([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(false)
  const [showForm, setShowForm] = useState(false)

  useEffect(() => {
    const controller = new AbortController()
      ; (async () => {
        let response
        setLoading(true)
        setError(false)

        try {
          response = await axios.get('/api/jokes', {
            signal: controller.signal
          })
          console.log(response)
          setJokes(response.data)
        } catch (e) {
          console.log(e)
          if (axios.isCancel(e)) {
            console.log("aborted")
          } else {
            setError(true)
          }
          return
        } finally {
        }
        
        setLoading(false)
      })()

    return () => {
      console.log("no don't render")
      controller.abort()
    }
  }, [])



  return (
    <div className="App">

      {loading && <div>Loading...</div>}
      {error && <div>Error</div>}

      {jokes.map((joke) => (
        <div key={joke.id}>
          <h3>{joke.text}</h3>
        </div>
      ))}

      {showForm ?
        <>
          <NewJokeForm onNewJoke={joke => setJokes([joke, ...jokes])} />
          <button onClick={() => setShowForm(false)}>Cancel</button>
        </>
        :
        <button onClick={() => setShowForm(true)}>New Joke</button>
      }

    </div>
  )
}

export default App

NewJokeForm.jsx

import { useState } from 'react'
import axios from 'axios'
import { useRef, useEffect } from 'react'

export default function NewJokeForm({onNewJoke}) {
  const [text, setText] = useState('')
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(false)

  const abortController = useRef(null)

  const abortNetworkRequest = () => {
    console.log("aborting")
    abortController.current?.abort()
  }

  useEffect(() => {
    return abortNetworkRequest
  }, [])

  const handleSubmit = async (e) => {
    abortNetworkRequest()
    abortController.current = new AbortController()
    e.preventDefault()
    setLoading(true)
    setError(false)

    try {
      let result = await axios.post('/api/jokes', { text })
      onNewJoke(result.data)
    } catch (e) {
      setError(true)
    } finally {
      setLoading(false)
    }
  }

  return (
    <>
      {loading ? <div>Loading...</div> :
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            value={text}
            onChange={(e) => setText(e.target.value)}
          />
          <button type="submit">Submit</button>
        </form>
      }
      {error && <div>Error</div>}
    </>
  )
}

Find an issue with this page? Fix it on GitHub