9

I am a beginner.I am trying to implement a POST request from React.js in a simple form, but I cannot figure out how to send POST request to database. I guess I need <form action="URL"> as well. Any help will be appreciated. Below is the code from React.js(frontend)

import GameTestResult from './GameTestResult';

export default function App() {
 const[data, setData] = useState([]);
 const [formData, setFormData] = useState("");

 useEffect (() => {
  fetch('http://localhost:3000/game')
  .then(res => res.json()) 
 .then(result => setData(result.rows))
  .catch(err => console.log("error"))
  },[]);

  const handleChange = event => {
    setFormData(event.target.value)
    }
    
    const eventHandler = event => {
      event.preventDefault();
      setFormData("");
    }

  return (
    <div className="App">
        <form  method="post" onSubmit = {eventHandler}>
          <input value = {formData} onChange = {handleChange} />
          <button type="submit">click</button>
        </form>
      
      {data && data.map((element, index)=>(
            <GameTestResult
              name = {element.name}
              key={element.index}
            />
      ))} 

      </div>
  );
}

here is the code from express.js(backend)

var router = express.Router();
const pool = require("../config.js");
var cors = require('cors');



router.get("/game", cors(), (req, res) => {
  pool
    .query("SELECT * FROM game")
    .then((data) => res.json(data))
    .catch((e) => {
      res.sendStatus(404), console.log(e);
    });
});



router.post("/game", (req, res) => {
  const { name } = req.body; 
 
  pool
    .query('INSERT INTO game(name) values($1);', [name])
    .then(data => res.status(201).json(data))
    .catch(e => res.sendStatus(404));
 });
 

module.exports = router;
FD3
  • 1,462
  • 6
  • 24
  • 47
  • Yes, API works. I have no errors, Post request works in backend when I tested via Postman. Now I cannot do Post request in Form using React.js. In this code I have no error , but database is not populated after clicking Form ‘click’ button – FD3 May 24 '20 at 13:41
  • Backend is in port 5000, and frontend in 3000 port and works fine – FD3 May 24 '20 at 13:42
  • API is called correctly, I can at least show GET request in React.js – FD3 May 24 '20 at 14:00
  • What's the exact problem? Are you able to make GET request, but not the POST? Does the answer below work for you? – Ajeet Shah May 24 '20 at 14:02
  • 1
    yes, that's my problem. And I didn't understand, what he below mean with 'event target key' expression – FD3 May 24 '20 at 14:11
  • `event.target.name` inside a `formHandler` function gives you **name** attribute value present inside the form. Read [more](https://stackoverflow.com/a/21031832/2873538) – Ajeet Shah May 24 '20 at 14:58

2 Answers2

10

Here is what you can do:

Fetch games when component is mounted. And Submit new game when form is submitted.

export default function App() {
  const [data, setData] = useState([])
  const [formData, setFormData] = useState('')

  useEffect(() => {
    fetchGames() // Fetch games when component is mounted
  }, [])

  const fetchGames = () => {
    fetch('http://localhost:3000/game', {
      method: 'GET',
    })
      .then((res) => res.json())
      .then((result) => setData(result.rows))
      .catch((err) => console.log('error'))
  }

  const saveGames = () => {
    fetch('http://localhost:3000/game', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        name: formData, // Use your own property name / key
      }),
    })
      .then((res) => res.json())
      .then((result) => setData(result.rows))
      .catch((err) => console.log('error'))
  }

  const handleSubmit = (event) => {
    event.preventDefault()
    saveGames() // Save games when form is submitted
  }

  const handleChange = (event) => {
    setFormData(event.target.value)
  }

  return (
    <div className="App">
      {/* method="post" not needed here because `fetch` is doing the POST not the `form` */}
      {/* Also, note I changed the function name, handleSubmit */}
      <form onSubmit={handleSubmit}>
        <input type="text" name="name" value={formData} onChange={handleChange} />
        <button type="submit">click</button>
      </form>

      {data &&
        data.map((element, index) => (
          <GameTestResult name={element.name} key={element.index} />
        ))}
    </div>
  )
}

You can read this about how to use fetch and this about how forms work in RecatJS.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • Also, you should consider using axios instead of fetch. Axios works better on old browsers too. See [this](https://stackoverflow.com/q/40844297/2873538) – Ajeet Shah May 24 '20 at 15:02
  • 1
    Thank you. to be honest, I didn’t use it before, but will learn as well – FD3 May 24 '20 at 15:06
4
  • Add name as "name" to input
  • Listen onChange and set data setFormData({[event.target.key]: event.target.value}) the data will be for example {name: "Tony"}
  • Call POST request on onClick action of button like code below
  • JSON.stringify(data) is important to convert js object to JSON when sending it to server
import GameTestResult from './GameTestResult'

export default function App() {
  const [data, setData] = useState([])
  const [formData, setFormData] = useState({})

  useEffect(() => {
    fetch('http://localhost:3000/game')
      .then((res) => res.json())
      .then((result) => setData(result.rows))
      .catch((err) => console.log('error'))
  }, [])

  const handleChange = (event) => {
    setFormData({ [event.target.name]: event.target.value })
  }

  const eventHandler = (event) => {
    fetch('http://localhost:3000/game', {
      method: 'POST',
      body: JSON.stringify(formData),
    })
      .then((res) => res.json())
      .then((result) => {
        console.log(result)
        setFormData('')
      })
      .catch((err) => console.log('error'))
  }

  return (
    <div className="App">
      <form>
        <input name="name" value={formData.name || ''} onChange={handleChange} />
        <button onClick={eventHandler}>click</button>
      </form>

      {data &&
        data.map((element, index) => (
          <GameTestResult name={element.name} key={element.index} />
        ))}
    </div>
  )
}
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
Tony Nguyen
  • 3,298
  • 11
  • 19
  • thanks for responding. I didn't understand only this part ---> setFormData({[event.target.key]: event.target.value}). Can you explain, please? – FD3 May 24 '20 at 14:04
  • `` when `handleOnchange` is triggered you get an `event`, we will have `event.target` is an object which has properties of the input element. Fir this input, we have `event.target.key` is `"name"` and `event.target.value` is whatever string user typed. Then, `{[event.target.key]: event.target.value}` will become `{name: "the string user type}`. then you set it as `formData` – Tony Nguyen May 24 '20 at 14:18
  • yes, I tried this way, but this doesn't allow me to type in input because now inside is '[object Object]' , when I try to type. and it sends empty rows to database – FD3 May 24 '20 at 14:22
  • Sorry my bad, `event.target.key` should be `event.target.name` and `` should be ``. `{formData.name || "} ` mean if there is `name property in `formData` object show `name` if it undefined show empty. I updated my comment, please check it for updated info – Tony Nguyen May 24 '20 at 14:25
  • it still sends empty rows to server – FD3 May 24 '20 at 14:37
  • @Gregfan I am not sure what step we did wrong.You can `console.log(formData)` before `fetch..` in `eventHandler ` function – Tony Nguyen May 24 '20 at 14:46
  • 1
    @Gregfan. I am glad it helps. Please give it a vote if it really helps you. – Tony Nguyen May 24 '20 at 15:26