函数中使用状态变量时状态未定义

时间:2019-06-02 15:43:53

标签: reactjs react-hooks

我有一个状态变量,正在通过Websocket更新。在记录变量以检查其状态时,它已经正确更新,但是当我在要使用的函数中引用它时,它是未定义的。我是React和State的新手,不确定自己在做什么错。

在我使用${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 :(得分:0)

我建议从一个基于类的组件开始,而不是从一个功能性的组件开始

创建一个内部带有状态对象的构造函数

并使用componentDidMount生命周期从套接字获取数据,并在组件正确安装后使用setState函数将其保存到状态

componentDidMount生命周期将重新渲染DOM,因此它看起来像是初始渲染。如果获取速度很慢,您会暂时看到它空白,然后将其呈现为所需的状态(它将呈现两次:一次是在获取数据之前,一次是在获取数据完成之后,因此请记住这一点可以在https://reactjs.org/docs/state-and-lifecycle.html处找到有关生命周期的更多信息

您可以使用Redux从Websocket进行提取并将其保存到Redux存储,然后使用它来更新您的组件

希望我的回答有所帮助

答案 1 :(得分:0)

对于您的第一个setContactCalling调用,setContactCalling是一个异步函数。在那样的情况下立即调用它并不能保证值已更改(事实上,它很可能尚未更改)。但是,一旦状态改变,您就可以依靠react再次渲染组件。不用发出警报,只需使用组件中的值即可。也许可以使用模态代替。

对于useEffect内的第二次调用,您尝试将contactCalling传递给该函数...但是该值未定义,因为useEffect不会将任何值传递给该函数。因此它将注销为undefined。值contactCalling将通过useEffect回调之外的setContactCalling设置。与其像您那样传递它,不如将其添加到值数组中以供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])