Search code examples
javascriptreactjsdestructuring

Why the results of the scripts are different?


In the first code I need to click one time on the button to present the list of "todo"s and in the second code I need to click twice to present a list of "todo"s.

The difference is inside the getUser and it's a destructuring change.

------1

import React, { useState } from 'react'
import axios from 'axios'

const TODOS_URL = 'https://jsonplaceholder.typicode.com/todos';
const USERS_URL = 'https://jsonplaceholder.typicode.com/users';

const UsersAndTodos = () => {
  const [id, setId] = useState('')
  const [user, setUser] = useState({name: '', email: ''})
  const [TodosTitles, setTodosTitles] = useState([])
  const receiveId = (e) => {
    setId(e.target.value)
  }
  const getUser = async () =>{
    const {data: user} = await axios.get(`${USERS_URL}/${id}`)

    setUser({name: user.name, email: user.email})

    if (user.name.startsWith('E')) {
      const { data: userTodos } = await axios.get(`${TODOS_URL}?userId=${id}`)
      const titles = userTodos.map((todo) => todo.title)
      setTodosTitles(titles)
    } else {
      setTodosTitles([]);
    }
  }

  return (
    <>
    <input type='number' onChange={receiveId}/>
    <button onClick={getUser}>send to data base</button>

    <h1>{id}</h1>
    <h1>{user.name}</h1>
    <h1>{user.email}</h1>
    <br />
    <ul>
      {TodosTitles.map((title,index)=>{
        return <li key={index}>{title}</li>
      })}
    </ul>

    </>  
    
    
  )
}

export default UsersAndTodos

------2
the same as 1 just the change inside getUser:


  const getUser = async () =>{
    const resp = await axios.get(`${USERS_URL}/${id}`)

    setUser({name: resp.data.name, email: resp.data.email})


Solution

  • In your first example:

        const {data: user} = await axios.get(`${USERS_URL}/${id}`)
    
        setUser({name: user.name, email: user.email})
    
        if (user.name.startsWith('E')) {
          const { data: userTodos } = await axios.get(`${TODOS_URL}?userId=${id}`)
          const titles = userTodos.map((todo) => todo.title)
          setTodosTitles(titles)
        } else {
          setTodosTitles([]);
        }
      }
    
    • You set a constant user within this function.
    • So when you get to if (user.name.startsWith('E')) { it can use user from the response constant to go into the if statement
    • This means you only click once
    • In your getUser function I would avoid using the const user as it is confusing with the user in your setState

    In your second example:

      const getUser = async () =>{
        const resp = await axios.get(`${USERS_URL}/${id}`)
    
        setUser({name: resp.data.name, email: resp.data.email})
    
        if (user.name.startsWith('E')) {
          const { data: userTodos } = await axios.get(`${TODOS_URL}?userId=${id}`)
          const titles = userTodos.map((todo) => todo.title)
          setTodosTitles(titles)
        } else {
          setTodosTitles([]);
        }
      }
    
    • You are using the user from the useState const [user, setUser] = useState({name: '', email: ''})
    • As setState is asynchronous, when it gets to the if statement on the first click user has not been set
    • When you click the second time the state has been set and so will now go into the if statement

    Point to note

    • When you click the second time, you are performing another get request but the user state is likely to still be the value set in the first request