React useState in Context остается неопределенным даже после использования setState

У меня возникла проблема с контекстом React. Я пытаюсь использовать setState, но значение состояния остается неопределенным.

Контекст.js

import {
  createContext,
  useContext,
  useMemo,
  useState,
  useEffect
} from "react";

const PlayerGamepadContext = createContext();

export const PlayerGamepadProvider = ({
  ...props
}) => {
  const [gamepads, setGamepads] = useState([])
  const [gamepadsCount, setGamepadsCount] = useState(0)
  const [mappedGamepads, setMappedGamepads] = useState([])

  // Triggered when button state change
  // (button: string, isPressed: bool, controllerIndex: integer) => void
  const [onButtonStateChanged, setOnButtonStateChanged] = useState(undefined)

  useEffect(() => {
    console.info("STATE CHANGED")
    console.info(setOnButtonStateChanged);
    console.info(onButtonStateChanged); // This shouldn't be undefined after I call "setOnButtonStateChanged"
  }, [onButtonStateChanged])

  const value = useMemo(() => {
    return {
      gamepads,
      mappedGamepads,
      playerCount: mappedGamepads?.length,
      setOnButtonStateChanged,
      setOnGamepadConnected
    }
  }, [
    gamepads,
    mappedGamepads,
    setOnButtonStateChanged,
    setOnGamepadConnected
  ])

  if (typeof window === 'undefined') {
  return "Loading";
}

  return <PlayerGamepadContext.Provider value = {value} {...props} />
}

export const usePlayerGamepads = () => {
  const context = useContext(PlayerGamepadContext)
  return context
}

Компонент.jsx

import React, { useEffect } from 'react'
import { usePlayerGamepads } from '@/components/Context/PlayerGamepadContext'

const TestController = props => {
  const [state, setState] = React.useState(undefined)
  const [init, setInit] = React.useState(false)
  const playerGamepads = usePlayerGamepads()

  const handleChangeEvent = (button, isPressed, index) => {
    console.info(button, isPressed, index);
  };

  useEffect(() => {
    setState(playerGamepads)
    if (playerGamepads && !init) {
      setInit(true)
      console.info("CALL SET STATE");
      playerGamepads.setOnButtonStateChanged(handleChangeEvent)
    }
  }, [playerGamepads]);

  return (
    <div></div>
  )
}

export default TestController

А вот вывод консоли

1- CALL SET STATE
2- undefined undefined undefined
3- STATE CHANGED
4- ƒ dispatchSetState(fiber, queue, action) {........
5- undefined

Я немного запутался, почему моя функция handleChangeEvent вызывается после использования setOnButtonStateChanged (строка вывода 2) но что более важно, почему onButtonStateChanged все еще не определено после его изменения?

Я попытался передать функцию через реквизит PlayerGamepadProvider, и это сработало, но мне нужно иметь возможность установить ее из состояния.

Я также пытался присвоить onButtonStateChanged значение по умолчанию.

const [onButtonStateChanged, setOnButtonStateChanged] = useState(console.info)

но вместо этого он напрямую принимает неопределенное значение

Заранее спасибо за помощь

Пожалуйста, сделайте codeandbox и поделитесь воспроизводимым примером

Slava Knyazev 03.04.2023 18:54

Вы должны обернуть свой корень с помощью <PlayerGamepadContext.Provider value = {value} /> вместо return <PlayerGamepadContext.Provider value = {value} {...props} /> из Context.js

Naveed Khan 03.04.2023 18:59
Поведение ключевого слова "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) для оценки ваших знаний,...
0
2
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы устанавливаете результат handleChangeEvent как OnButtonStateChanged, поэтому вызывается журнал консоли, а результат не определен.

Вместо:

playerGamepads.setOnButtonStateChanged(handleChangeEvent)

Пытаться:

playerGamepads.setOnButtonStateChanged(() => handleChangeEvent)

@Maxime, если вы хотите знать, почему, ознакомьтесь с этим часто задаваемым вопросом в документации по реакции.

Fitzi 03.04.2023 19:32

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