4

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'));
 }

4 Answers 4

2

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>
);

}

Sign up to request clarification or add additional context in comments.

1 Comment

I guess the loading should be false then become true , right?
1

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

1 Comment

Thank you, but the problem is when i try to render students.data in jsx without JSON.stringify it returns error that students.data is undefined. Do I need to use UseEffect hook ?
0

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.

Comments

0
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

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.