Почему я не могу установить массив в useEffect?

Я изучаю React и пытаюсь написать асинхронный хук. Использование setResult внутри useEffect, похоже, не работает. Когда я попытался отобразить результат, ничего не было, поэтому я добавил несколько консольных журналов, чтобы увидеть, что происходит. Функция установки в хуке useState, похоже, ничего не делает. Я следил за этим видео для получения некоторого руководства, и мой код не слишком сильно отличается.

У меня есть следующий компонент:

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

const Search = () => {
  const [search, setSearch] = useState('')
  const [query, setQuery] = useState('')
  const [result, setResult] = useState([])

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(
          `https://api.spotify.com/v1/search?q=${encodeURIComponent(
            query
          )}&type=track`,
          {
            method: 'GET',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
              Authorization: 'Bearer ' + auth.access_token
            }
          }
        )
        const json = await response.json()
        console.log({ json })
        console.log(
          json.tracks.items.map(item => {
            return item.id
          })
        )
        setResult(
          json.tracks.items.map(item => {
            return item.id
          })
        )
        console.log({result})
      } catch (error) {
        console.log(error)
      }
    }

    if (query !== '') {
      fetchData()
    }
  }, [query])

  return (
    <div>
      <input
        value={search}
        placeholder='Search...'
        onChange={event => setSearch(event.target.value)}
        onKeyPress={event => {
          if (event.key === 'Enter') {
            setQuery(search)
          }
        }}
      ></input>
      <br />
      {result.map(item => (
        <h3 key={item}></h3>
      ))}
    </div>
  )
}

export default Search

От console.log ({ json }) я вижу, что ответ сервера выглядит нормально.

console.log(
    json.tracks.items.map(item => {
        return item.id
    })
)

Приведенный выше вывод консоли также выглядит нормально.

setResult(
  json.tracks.items.map(item => {
    return item.id
  })
)
console.log({result})

Почему result пусто?

РЕДАКТИРОВАТЬ: Спасибо, Патрик и Талгат. Теперь я понимаю. Итак, когда я console.log вне useEffect, я мог видеть, что result установлен правильно. Затем я понял, что в моем рендере отсутствует ссылка на {item}:

{result.map(item => (
  <h3 key={item}>{item}</h3>
))}

Теперь я вижу идентификаторы, отображаемые на странице. Спасибо за вашу помощь.


person Marek Siekierski    schedule 26.09.2019    source источник
comment
setResult() не обновляет состояние синхронно, он публикует обновление, которое происходит в запланированном микротике, и запускает повторный рендеринг компонента с обновленным result. В следующий раз, когда const [result, setResult] = useState([]) будет оцениваться при повторном рендеринге, then result будет содержать обновленный массив.   -  person Patrick Roberts    schedule 27.09.2019
comment
Попробуйте console.log(result) за пределами useEffect   -  person Talgat Saribayev    schedule 27.09.2019
comment
Спасибо. Редактировал вопрос. Теперь это работает.   -  person Marek Siekierski    schedule 27.09.2019


Ответы (1)


setTimeout(()=>{
console.log(result);
},0);

Попробуйте вместо этого использовать console.log(result). Состояние настройки не обновляется, как только вы вставляете значение через сеттер (на вашей стороне setResult). Так что для этого нужна задержка.

person topDev    schedule 26.09.2019