Как я могу разделить состояние между двумя пользовательскими хуками?

Я пытаюсь получить данные из Spotify API. Поскольку для этого мне нужен токен доступа, я создал собственный хук для анализа токена из URL-адреса, который приходит с сервера. У меня также есть еще один пользовательский хук с фактическим запросом к API, который принимает проанализированный токен в качестве аргумента. Оба собираются в родительский крючок.

Я не могу заставить это работать, так как токен никогда не достигает области действия хука запроса, поэтому он терпит неудачу. Если я разбираю токен и делаю запрос в том же хуке, все работает нормально. Я намеревался сделать хук для каждого запроса, так как это не один, поэтому я хотел передать токен в качестве аргумента.

Пользовательский хук токена

export default () => {
  const [ token, setToken ] = useState('')
  useEffect(() => {
    const { access_token } = queryString.parse(window.location.search)
    return setToken(access_token)
  }, [])
  return token
}

Запрос крюка

export default function useFetchUserData(token) {
  //state
  const initialUserState = {
    display_name: '',
    external_url: '',
    images: ''
  }
  const [ userData, setUserData ] = useState(initialUserState)
  const [ isLoading, setIsLoading ] = useState(false)
  const [ isError, setIsError ] = useState(false)

  useEffect(() => {
    async function getUserData() {
      setIsLoading(true);
      setIsError(false);

      const spotify = axios.create({
        baseURL: 'https://api.spotify.com/v1/me',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      })
      try {
        const userRes = await spotify('/')
        .then( res => { return res.data });

        setUserData({
          display_name: userRes.display_name,
          external_url: userRes.external_urls.spotify,
          images: userRes.images[0].url
        })
      } catch (error) {
          setIsError(true)
      }
      setIsLoading(false);
    }
    getUserData();
  }, [])

  const data = {
    userData,
    isLoading,
    isError
  }
  return data
}

Родительский крючок

export default function Home() {

  const  token = useParseToken()
  const { userData, isLoading, isError } = useFetchUserData(token);

  if (isLoading) return <BarLoader />;
  if (isError) return <div>Oops! something went wrong</div>;

  return (
    <Fragment>
      <Header userData = {userData}/>
    </Fragment>  
  )   
}

Привет @FedericoCastro, взгляните на новый API контекста. Похоже, это было бы идеально для вашего случая использования! Частью хуков был хук useContext, который упрощает работу с контекстом!

Jared 01.05.2019 05:06

Из вашего примера кода const { token } = useTokenParser() может быть неправильно, должно быть const token = useTokenParser()

hackape 01.05.2019 06:17

Затем внутри useFetchUserData вы должны правильно обработать случай, когда token === "", потому что первый вызов всегда получает этот случай.

hackape 01.05.2019 06:19

Большое спасибо @hackape, это сработало. Я слишком увлекся деструктурированием.

fred0 01.05.2019 06:42

спасибо @Jared, возможно, пришло время попробовать!

fred0 01.05.2019 06:43
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
326
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны использовать createContext API реакции. Сохраните токен как контекст. и используйте его где угодно. Я думаю, этот репозиторий вам поможет.

Ответ принят как подходящий

В вашем случае происходит то, что вы устанавливаете состояние в хуке useEffect в своем пользовательском хуке, чтобы установить токен. Однако вы возвращаете токен из этого хука, не дожидаясь запуска эффекта, поэтому при первом вызове вашего useFetchUserData хука он получит пустую строку в качестве токена. Чтобы решить эту проблему, вы должны реализовать хук useFetchUserData для запуска после того, как токен станет доступен или изменится.

export default function useFetchUserData(token) {
  //state
  const initialUserState = {
    display_name: '',
    external_url: '',
    images: ''
  }
  const [ userData, setUserData ] = useState(initialUserState)
  const [ isLoading, setIsLoading ] = useState(false)
  const [ isError, setIsError ] = useState(false)

  useEffect(() => {
    async function getUserData() {
      setIsLoading(true);
      setIsError(false);

      const spotify = axios.create({
        baseURL: 'https://api.spotify.com/v1/me',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      })
      try {
        const userRes = await spotify('/')
        .then( res => { return res.data });

        setUserData({
          display_name: userRes.display_name,
          external_url: userRes.external_urls.spotify,
          images: userRes.images[0].url
        })
      } catch (error) {
          setIsError(true)
      }
      setIsLoading(false);
    }
    if (token !== '' || token !== null) {
       getUserData();
    }
  }, [token])

  const data = {
    userData,
    isLoading,
    isError
  }
  return data
}

Кроме того, поскольку useParseToken возвращает токен, вам не нужно деструктурировать его при использовании

const token = useParseToken();

Другие вопросы по теме