Artsiom Aliaksandrau
Artsiom Aliaksandrau

Reputation: 69

react fetch data on button click

I'm trying to fetch data in react. The problem is i have to click on button twice to get that data. Although i don't get data on first click it somehow renders if I add JSON.stringify to it. If I don't add JSON.stringify it returns undefined. If anyone know what this is please help me

without clicking
on first click
on second click

import React, {useState,useEffect} from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios'

function Example() {

const [students,setStudents] = useState('')
const [name,setName] = useState('')

const handleClick = async() => {
    const data = await axios.get('api/foo')
    setStudents(data)
    console.log(students)
}

return (
    <div className="container">
        <h2>Example component</h2>
        <button onClick = {handleClick}>Get students</button>
        <div>
            {JSON.stringify(students.data)}
        </div>
    </div>
);
 }

export default Example;

if (document.getElementById('root')) {
     ReactDOM.render(<Example />, document.getElementById('root'));
 }

Upvotes: 4

Views: 23438

Answers (4)

Marwen khamassi
Marwen khamassi

Reputation: 1

import { useState } from "react"

function App() {
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)
  const [loading, setLoading] = useState(false)

  function fetchHanlde() {
    const url = 'https://jsonplaceholder.typicode.com/posts'
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false)
      })
      .catch((error) => {
        setError(error)
        setLoading(false)
      })
      .finally(() => setLoading(false))

    return { data, loading, error }
  }

  return <>
    <h1>hook pesonnalisé  </h1>
    <button onClick={fetchHanlde}>get posts</button>

    {loading && <div>Loading...</div>}
    {data && <div>
      <ul>
        {data.map(post => (<li key={post.id}>{post.title}</li>))}
      </ul>
    </div>}
    {error && <div>error  : {error.message}</div>}
  </>
}


export default App

Upvotes: 0

Artsiom Aliaksandrau
Artsiom Aliaksandrau

Reputation: 69

The problem was that setStudents is an asynchronous function, so I just made student object and added to it loading property

const [students,setStudents] = useState({
    data: '',
    loading: true
})
const [name,setName] = useState('')

const handleClick = async() => {
    const data = await axios.get('api/foo')
    setStudents({
        data: data,
        loading: false
    })
}

return (
    <div className="container">
        <h2>Example component</h2>
        <button onClick = {handleClick}>Get students</button>
        <div>
            {students.loading?'':
            students.data.data[0].name}
        </div>
    </div>
);

}

Upvotes: 2

Rudraprasad Das
Rudraprasad Das

Reputation: 368

setStudent is an asynchronous function. This means the value of students won't change immediately after you call setStudents.

Try shifting the console.log outside the handleClick function. Like this -

import React, {useState,useEffect} from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios'

function Example() {

const [students,setStudents] = useState('')
const [name,setName] = useState('')

const handleClick = async() => {
    const data = await axios.get('api/foo')
    setStudents(data)
}

console.log(students)

return (
    <div className="container">
        <h2>Example component</h2>
        <button onClick = {handleClick}>Get students</button>
        <div>
            {JSON.stringify(students.data)}
        </div>
    </div>
);
 }

export default Example;

if (document.getElementById('root')) {
     ReactDOM.render(<Example />, document.getElementById('root'));
 }

Initially, the value will be an empty string, then it will change to the value from api/foo

Upvotes: 1

Shmili Breuer
Shmili Breuer

Reputation: 4147

React hooks are async so when you are running console.log(students) right after running setStudents(data) it is still not populated, however the 2nd time you click the button it is already populated from the first time you clicked it.

If you want to console the result right after the state setter runs you can see this answer on another question.

Upvotes: 0

Related Questions