javascript - 为什么要执行前一个屏幕组件中的 socket.on() ?

标签 javascript reactjs react-native socket.io

我有两个 react 组件。第一个Lobby使用react-native-navigation将Gameroom推送到堆栈。它将套接字对象和其他数据等 Prop 传递给 Gameroom 组件

当在 Gameroom 内按下导航栏的后退按钮时,会发出一个 socket.io leave 事件,并且我已经验证服务器能够听到该事件,因此通过 props 传递的套接字有效。然后,服务器将 left 事件发送回 socket.io room(Gameroom 组件)。

如果将 left 事件监听器放置在 Gameroom 的 componentDidMount() 内部,则不会执行。但是,如果将相同的 socket.io 事件监听器放置在 Lobby 组件(上一屏幕)componentDidMount() 中,则会听到该事件

我尝试将事件监听器添加到多个 componentDidMount 函数,我还考虑过使用 Context API,但我不使用嵌套组件。我正在将react-native-navigation的{passProps}中的套接字对象从一个屏幕传递到另一个屏幕

Lobby:

imports ...
const socket = io("http://192.xxx.xxx.xx:3000");
export default class Lobby extends React.Component {
  static options(passProps) {
    return {
      topBar: {
        background: {
          color: "transparent"
        },
        drawBehind: true,
        visible: true,
        animate: true,
        leftButtons: [
          {
            id: "leave",
            icon: require("../assets/img/Chevron.png")
          }
        ]
      }
    };
  }
  constructor(props) {
    super(props);
    this.state = {
      username: "Initializing...",
      queue: []
    };
  }
  componentDidMount() {
    Navigation.events().bindComponent(this);
    socket.emit("lobbyEntry");
    socket.on("lobbyEntry", entry => {
      this.setState({ queue: entry.lobby, username: socket.id });
    });
    socket.on("userJoined", lobby => {
      this.setState({ queue: lobby });
    });
    // socket.on("left", () => {
    //   alert("Opponent Left...Oh well");
    //   Navigation.pop(this.props.componentId);
    // });
  }
  navigationButtonPressed({ buttonId }) {
    switch (buttonId) {
      case "leave":
        socket.emit("leave");
        Navigation.popToRoot(this.props.componentId);
        break;
    }
  }
  createMatch = () => {
    if (this.state.username != "Initializing...") {
      socket.emit("findMatch");
      socket.on("alreadyCreated", () => {
        alert("You already created a match!");
      });
      socket.on("listUsers", lobby => {
        this.setState({ queue: lobby });
      });
      socket.on("matchFound", data => {
        Navigation.push(this.props.componentId, {
          component: {
            name: "Gameroom",
            passProps: {
              room: data.id,
              socket: socket,
              firstMove: data.firstMove,
              p1: data.p1,
              p2: data.p2
            }
          }
        });
      });
    } else {
      alert("Wait for Username to be initialized...");
    }
  };
  render() {
    const bg = getBackground();
    return (
      <ImageBackground source={bg} style={{ height: "100%", width: "100%" }}>
        <View style={styles.title_container}>
          <Text style={styles.title_sm}>Matchmaking Lobby</Text>
        </View>
        <View style={styles.alt_text_container}>
          <Text style={styles.alt_text_md}>Username:</Text>
          <Text style={styles.alt_text_md}>{this.state.username}</Text>
        </View>
        <View
          style={{
            flexDirection: "column",
            justifyContent: "center",
            alignItems: "center"
          }}
        >
          <XplatformButton onPress={this.createMatch} text={"Create a Match"} />
        </View>
        <View style={styles.alt_text_container}>
          <Text style={styles.alt_text_sm}>Players actively searching...</Text>
          <FlatList
            style={styles.alt_text_container}
            data={this.state.queue}
            renderItem={({ item, index }) => (
              <Text style={styles.alt_text_md} key={index}>
                {item}
              </Text>
            )}
          />
        </View>
      </ImageBackground>
    );
  }
}

游戏室:

import ...
export default class Gameroom extends React.Component {
  static options(passProps) {
    return {
      topBar: {
        title: {
          fontFamily: "BungeeInline-Regular",
          fontSize: styles.$navbarFont,
          text: "Gameroom - " + passProps.room,
          color: "#333"
        },
        background: {
          color: "transparent"
        },
        drawBehind: true,
        visible: true,
        animate: true,
        leftButtons: [
          {
            id: "leave",
            icon: require("../assets/img/Chevron.png")
          }
        ]
      }
    };
  }
  constructor(props) {
    super(props);
    Navigation.events().bindComponent(this);
  }

  navigationButtonPressed({ buttonId }) {
    switch (buttonId) {
      case "leave":
        this.props.socket.emit("leave");
        Navigation.pop(this.props.componentId);
        break;
    }
  }

  componentDidMount() {
    // socket.on("left", () => {
    //   alert("Opponent Left...Oh well");
    //   Navigation.pop(this.props.componentId);
    // });
  }

  render() {
    const bg = getBackground();
    return this.props.p2 != null ? (
      <Gameboard
        room={this.props.room}
        you={
          this.props.socket.id == this.props.p1.username
            ? this.props.p1.marker
            : this.props.p2.marker
        }
        opponent={
          this.props.socket.id != this.props.p1.username
            ? this.props.p2.marker
            : this.props.p1.marker
        }
        move={this.props.firstMove}
        socket={this.props.socket}
      />
    ) : (
      <ImageBackground style={styles.container} source={bg}>
        <View style={{ marginTop: 75 }}>
          <Text style={styles.alt_text_md}>
            Waiting for Opponent to Join...
          </Text>
        </View>
      </ImageBackground>
    );
  }
}

我希望事件监听器从当前屏幕的 componentDidMount() 函数执行,但仅当它位于前一个屏幕的 componentDidMount() 内部时才会执行

最佳答案

当您创建组件时,

the constructor -> componentWillMount -> render -> componentDidMount is followed.

在您的 Lobby 类中,事件监听器会运行,因为它位于 ComponentDidmont 中。

但是,Gameroom 类的事件监听器位于构造函数 内部。如果在构造函数内执行,则无法听到该事件,因为它尚未渲染

事件监听器在屏幕上出现时被调用

使用

  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

关于javascript - 为什么要执行前一个屏幕组件中的 socket.on() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57454125/

相关文章:

javascript - 以随机顺序打印数组?

javascript - Vue.js 参数化变量名称

javascript - 按首字母 Javascript 的字母顺序对对象进行排序和分组

javascript - 测试异步useEffect

node.js - React 没有获取环境变量

jquery - 如何将自定义 JS 文件包含到 React 创建应用程序中

javascript - React Native fetch() 返回奇怪的 json 响应项

javascript - 当脚本插入 DOM 时,jQuery .on() 未绑定(bind)

javascript - 从 Cheerio 抓取 Youtube 数据

reactjs - React/React Native + enzyme : How to test if a component renders it's children?