Состояние не определено, когда переменные состояния используются в функциях - PullRequest
0 голосов
/ 02 июня 2019

У меня есть переменная в состоянии, которое я обновляю через websocket.При регистрации переменной для проверки ее состояния она обновилась правильно, но когда я ссылаюсь на нее в функции для использования, она не определена.Я новичок в React и заявляю, и не уверен, что я делаю неправильно.

В обеих строках, где я использую ${contactCalling}, оно отображается как неопределенное.

Любая помощь очень ценится!


import React from 'react';
import { useState, useEffect } from 'react';
import './App.css';
import socketIOClient from "socket.io-client";
import CallPane from './CallPane'
import '@opentok/client';

import {
    SERVER_BASE_URL,
} from './config';


const BASEURL = 'http://localhost:4001'
const socket = socketIOClient(BASEURL);

function App() {
    const [callFlag, setCallFlag] = useState(Boolean)
    const [apiData, setApiData] = useState([])
    const [contactCalling, setContactCalling] = useState('')

    console.log(contactCalling)

    socket.on("outgoing data", data => {
        console.log(data);
        setContactCalling(data.caller)
        alert(`${contactCalling} is calling you`)
        console.log('Call answered')
        setCallFlag(true);
    });

    useEffect ((contactCalling) => {
        fetch(SERVER_BASE_URL + `/room/${contactCalling}`)
            .then(data => data.json())
            .then(data => setApiData(data))
            .catch((err) => {
                console.error('Failed to get session credentials', err);
                alert('Failed to get opentok sessionId and token. Make sure you have updated the config.js file.');
            });
    },[])

    if (callFlag) {
        return (
            <div className="CallPane">
                <CallPane credentials={apiData}/>
            </div>
        );
    } else {
        return (
            <div className="CallPane">
            </div>
        );
    }
}

export default App;


Ответы [ 2 ]

0 голосов
/ 03 июня 2019

Для вашего первого вызова setContactCalling setContactCalling является асинхронной функцией. Вызов его сразу после этого не гарантирует, что значение было изменено (фактически, оно, скорее всего, еще не было изменено). Однако вы можете рассчитывать на реакцию для повторного рендеринга компонента после изменения состояния. Вместо предупреждения просто используйте значения в компоненте. Возможно, используйте вместо этого модальное.

Для второго вызова внутри useEffect вы пытаетесь передать contactCalling в функцию ... однако это значение не определено, поскольку useEffect ничего не передаст в него. Таким образом, он выйдет как неопределенный. Значение contactCalling будет установлено через setContactCalling вне обратного вызова useEffect. Вместо того, чтобы передавать его, как вы делаете, просто добавьте его в массив значений для useEffect, чтобы наблюдать следующим образом:

useEffect (() => {
    fetch(SERVER_BASE_URL + `/room/${contactCalling}`)
        .then(data => data.json())
        .then(data => setApiData(data))
        .catch((err) => {
            console.error('Failed to get session credentials', err);
            alert('Failed to get opentok sessionId and token. Make sure you have updated the config.js file.');
        });
},[contactCalling])
0 голосов
/ 03 июня 2019

Я бы рекомендовал начинать с компонента, основанного на классе, а не с функционального

создать конструктор с объектом состояния внутри него

и используйте жизненный цикл componentDidMount для извлечения данных из сокета и сохранения их в состояние с помощью функции setState после правильной установки компонента

жизненный цикл componentDidMount будет перерисовывать DOM, поэтому он будет выглядеть так, как будто это начальный рендер. Если выборка идет медленно, вы на мгновение увидите, что она пуста, а затем отрендерится до того, что вам нужно (она отрисовывает его дважды: один раз перед извлечением данных и один раз при извлечении данных, так что имейте это в виду, что вы Подробнее о жизненных циклах можно узнать здесь https://reactjs.org/docs/state-and-lifecycle.html)

вы можете использовать Redux для извлечения из веб-сокета и сохранения его в хранилище с резервной копией, а затем обновить его с помощью компонента

надеюсь, что мой ответ немного помог

...