Javascript ContextAPI:如何在React中的上下文之间共享数据?

Javascript ContextAPI:如何在React中的上下文之间共享数据?,javascript,reactjs,socket.io,react-context,Javascript,Reactjs,Socket.io,React Context,我的问题是: 我的网站的认证位是“完整的”。注册/登录后,用户将收到一个包含jwt令牌的cookie。接收到UserDataContext后,将向其提供用户的用户ID(uid)和用户名。uid用于服务器上的所有事情 io将用于通知后端从前端执行操作。套接字可用于通过react上下文对组件进行反应。我有两个上下文,UserDataContext和SocketContext。我需要跟踪哪个插座连接到哪个用户 我想我将在服务器上创建一个SocketManager类,它侦听新的套接字连接并通过uid将它

我的问题是:

我的网站的认证位是“完整的”。注册/登录后,用户将收到一个包含jwt令牌的cookie。接收到UserDataContext后,将向其提供用户的用户ID(uid)和用户名。uid用于服务器上的所有事情

io将用于通知后端从前端执行操作。套接字可用于通过react上下文对组件进行反应。我有两个上下文,UserDataContext和SocketContext。我需要跟踪哪个插座连接到哪个用户

我想我将在服务器上创建一个SocketManager类,它侦听新的套接字连接并通过uid将它们与用户关联。我试着用套接字的id来做这件事,但问题是id在重定向/刷新时会改变。因此,我需要一种通过套接字连接事件发送uid的方法。uid保存在UserDataContext中

如何将uid从UserDataContext获取到SocketContext?我应该合并这些上下文吗?这是正确的方向吗

App.js-

import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';

import UserDataContextProvider from './contexts/UserDataContext.js';
import SocketContextProvider from './contexts/SocketContext.js';

import Landing from './pages/Landing.js';
import Topnav from './pages/components/global/Topnav.js';
import UserDashboard from './pages/components/consoles/UserDashboard.js';

import './Global.css';


const App = props => (
  <div>
    <UserDataContextProvider>
      <Topnav />
      <SocketContextProvider>
        <Switch>
          <Route exact path='/' component={Landing} />
          <Route exact path='/dashboard/:id' component={UserDashboard} />
        </Switch>
      </SocketContextProvider>
    </UserDataContextProvider>
  </div>
);

export default App;
import React,{Component}来自'React';
从“react Router dom”导入{BrowserRouter as Router,Switch,Route,Link};
从“./contexts/UserDataContext.js”导入UserDataContextProvider;
从“./contexts/SocketContext.js”导入SocketContextProvider;
从“./pages/Landing.js”导入登录;
从“/pages/components/global/Topnav.js”导入Topnav;
从“./pages/components/consoles/UserDashboard.js”导入UserDashboard;
导入“/Global.css”;
const App=props=>(
);
导出默认应用程序;
UserDataContext.js-

import React, { Component, createContext } from 'react';

export const UserDataContext = createContext();

class UserDataContextProvider extends Component{
  state = {
    auth: false,
    uid: false,
    username: false
  };

  setUserData = data => {
    this.setState({uid: data.uid, username: data.tag})
  }

  render(){
    return (
      <UserDataContext.Provider value={{state: this.state, setUserData: this.setUserData}}>
        {this.props.children}
      </UserDataContext.Provider>
    );
  }
}

export default UserDataContextProvider;
import React, { Component, createContext } from 'react';

export const SocketContext = createContext();

import io from 'socket.io-client';
const prod = (process.env.NODE_ENV === "production");
const address = prod ? window.location.hostname : "http://localhost:8080";
const socket = io(address);

class SocketContextProvider extends Component{
  render(){
    return (
      <SocketContext.Provider value={{socket:socket}}>
        {this.props.children}
      </SocketContext.Provider>
    );
  }
}

export default SocketContextProvider;
import React,{Component,createContext}来自'React';
export const UserDataContext=createContext();
类UserDataContextProvider扩展组件{
状态={
作者:错,
uid:错,
用户名:false
};
setUserData=data=>{
this.setState({uid:data.uid,username:data.tag})
}
render(){
返回(
{this.props.children}
);
}
}
导出默认UserDataContextProvider;
SocketContext.js-

import React, { Component, createContext } from 'react';

export const UserDataContext = createContext();

class UserDataContextProvider extends Component{
  state = {
    auth: false,
    uid: false,
    username: false
  };

  setUserData = data => {
    this.setState({uid: data.uid, username: data.tag})
  }

  render(){
    return (
      <UserDataContext.Provider value={{state: this.state, setUserData: this.setUserData}}>
        {this.props.children}
      </UserDataContext.Provider>
    );
  }
}

export default UserDataContextProvider;
import React, { Component, createContext } from 'react';

export const SocketContext = createContext();

import io from 'socket.io-client';
const prod = (process.env.NODE_ENV === "production");
const address = prod ? window.location.hostname : "http://localhost:8080";
const socket = io(address);

class SocketContextProvider extends Component{
  render(){
    return (
      <SocketContext.Provider value={{socket:socket}}>
        {this.props.children}
      </SocketContext.Provider>
    );
  }
}

export default SocketContextProvider;
import React,{Component,createContext}来自'React';
export const SocketContext=createContext();
从“socket.io客户端”导入io;
const prod=(process.env.NODE_env==“production”);
const address=prod?window.location.hostname:“http://localhost:8080";
常量套接字=io(地址);
类SocketContextProvider扩展组件{
render(){
返回(
{this.props.children}
);
}
}
导出默认SocketContextProvider;

您需要使用用户数据上下文(或合并两个提供程序)将内容嵌套到SocketContextProvider。然后你可以:

  • 发送一条特殊消息,在新uid更改时通知服务器,或
  • 在您发送的每封邮件中发送uid
也就是说,使用上下文和提供者最有助于传播状态更改(如用户名、主题等),而不是像套接字这样的“活动对象”

对于您的情况,因为您已经有了一个用于套接字的模块级全局,所以放弃套接字的提供者和上下文并不是一个很大的罪恶,只需

import io from 'socket.io-client';
const prod = (process.env.NODE_ENV === "production");
const address = prod ? window.location.hostname : "http://localhost:8080";

let socket = null;

export function getSocket() {
  if(socket === null) {
    socket = io(address);
  }
  return socket;
}

从“/socket things”导入{getSocket};
常量MyComponent=()=>(
getSocket().send('foo')}/>
);

我想我在一个教程中看到了它与上下文一起使用,并使用了它。这是一个更好的主意。当你说这不是一个“大罪”时,你是在暗示这是一个较小的罪,并且有更好的方法来做到这一点吗?拥有全球国家使得孤立地测试事情变得更加困难。这就是说,这也是可以测试的,因为你可以添加一些机制来用合适的东西替换
socket
对象。Ps:我编辑了一些东西来创建和连接socket,只是在第一次真正需要的时候。如果你使用服务器端渲染,人们会共享socket…@quirimmo,不,web浏览器中的客户端无法与服务器上的同一套接字对象交互。在OP的用例中,看起来所有套接字交互都是经过身份验证的。