我的状态为空,当我尝试从函数中访问它时?

huangapple go评论72阅读模式
英文:

Why my state is empty when I try to access it from a function?

问题

I have this room component for video chat, it has two states, players to hold all elements, it is an array of nodes, each is a div, created when a user joins the room (this happens inside useEffect) and videoInDisplayFrame to hold the current element in display frame, when the user clicks on a specific player we set this one to videoInDisplayFrame.

import { useState, useEffect, useRef } from "react";
import styles from "./Room.module.css";

export default function Room() {
  const [players, setPlayers] = useState([]);
  const [videoInDisplayFrame, setVideoInDisplayFrame] = useState(null);

  const displayFrame_ref = useRef();
  const streams__container_ref = useRef();

  let expandVideoFrame = (e) => {
    console.log("expandVideoFrame is running... players:", players, "videoInDisplayFrame:", videoInDisplayFrame);

    displayFrame_ref.current.style.display = "block";

    //if videoInDisplayFrame is not null
    if (videoInDisplayFrame) {
      // add videoInDisplayFrame to players
      setPlayers((prev) => [...prev, videoInDisplayFrame]);
    }
    // find from players the one with the same id as e.currentTarget
    const newVideoInDisplayFrame = players.find((element) => 
      element.props.id === e.currentTarget.id
    );
    // then if it exists, add it to videoInDisplayFrame
    if (newVideoInDisplayFrame) {
      setVideoInDisplayFrame(newVideoInDisplayFrame);
    }
  };

  let hideDisplayFrame = () => {
    console.log("hideDisplayFrame is running... players:", players, "videoInDisplayFrame:", videoInDisplayFrame);

    displayFrame_ref.current.style.display = null;

    // add videoInDisplayFrame to players
    setPlayers([...players, videoInDisplayFrame]);

    // set videoInDisplayFrame to null
    setVideoInDisplayFrame(null);
    
  };

  useEffect(() => {
    console.log("useEffect is running...");
    // after component first mount
    let uid = String(Math.floor(Math.random() * 10000));
    // create JSX element
    let player = (
      <div
        className={styles.video__container}
        id={`user-container-${uid}`}
        onClick={expandVideoFrame}
      >
        <div className={styles.video_player} id={`user-${uid}`}></div>
      </div>
    );
    // add it to players
    setPlayers((prev) => [...prev, player]);
  }, []);

  return (
    <>
      {console.log("This is a new render... players: ", players, "and videoInDisplayFrame: ", videoInDisplayFrame)}
      <section
        className={styles.stream__container}
      >
        <div
          ref={displayFrame_ref}
          id="stream__box"
          className={styles.stream__box}
          onClick={hideDisplayFrame}
        >
          {videoInDisplayFrame}
        </div>

        <div
          ref={streams__container_ref}
          className={styles.streams__container}
        >
          {/* display players inside JSX */}
          {players.map((element, index) => (
            <div key={index}>{element}</div>
          ))}
        </div>
      </section>
    </>
  );
}

when I mount the components for the first time and then click on the only player I have to display it, I can see that my players state is an empty array, I expected it to contain the element so I can remove it and set it inside videoInDisplayFrame because useEffect should update it so the component rerenders and the state is updated before I click, I even added this button

<button
  onClick={() => {
   console.log("current state... players: ", players, "videoInDisplayFrame:", videoInDisplayFrame);
  }}
 >
current state
</button>

to be able to see the state at any moment and the output was confusing:
我的状态为空,当我尝试从函数中访问它时?

as you can see, even when I clicked on the button to see the state before expandVideoFrame and after it and it is not empty even when I click to run hideDisplayFrame after this, players is not empty so why it is when expandVideoFrame runs?.

英文:

I have this room component for video chat, it has two states, players to hold all elements, it is an array of nodes, each is a div, created when a user joins the room (this happens inside useEffect) and videoInDisplayFrame to hold the current element in display frame, when the user clicks on a specific player we set this one to videoInDisplayFrame.

import { useState, useEffect, useRef } from &quot;react&quot;;
import styles from &quot;./Room.module.css&quot;;

export default function Room() {
  const [players, setPlayers] = useState([]);
  const [videoInDisplayFrame, setVideoInDisplayFrame] = useState(null);

  const displayFrame_ref = useRef();
  const streams__container_ref = useRef();

  let expandVideoFrame = (e) =&gt; {
    console.log(&quot;expandVideoFrame is running... players:&quot;,players,&quot;videoInDisplayFrame:&quot;,videoInDisplayFrame);

    displayFrame_ref.current.style.display = &quot;block&quot;;

    //if videoInDisplayFrame is not null
    if (videoInDisplayFrame) {
      // add videoInDisplayFrame to players
      setPlayers((prev) =&gt; [...prev, videoInDisplayFrame]);
    }
    // find from players the one with the same id as e.currentTarget
    const newVideoInDisplayFrame = players.find((element) =&gt; 
      element.props.id === e.currentTarget.id;
    );
    // then if it exists, add it to videoInDisplayFrame
    if (newVideoInDisplayFrame) {
      setVideoInDisplayFrame(newVideoInDisplayFrame);
    }
  };

  let hideDisplayFrame = () =&gt; {
    console.log(&quot;hideDisplayFrame is running... players:&quot;,players,&quot;videoInDisplayFrame:&quot;,videoInDisplayFrame);

    displayFrame_ref.current.style.display = null;

    // add videoInDisplayFrame to players
    setPlayers([...players, videoInDisplayFrame]);

    // set videoInDisplayFrame to null
    setVideoInDisplayFrame(null);
    
  };

  useEffect(() =&gt; {
    console.log(&quot;useEffect is running...&quot;);
    // after component first mount
    let uid = String(Math.floor(Math.random() * 10000));
    // create JSX element
    let player = (
      &lt;div
        // ref={videoFrames_refs[videoFrames_refs.length]}
        className={styles.video__container}
        id={`user-container-${uid}`}
        onClick={expandVideoFrame}
      &gt;
        &lt;div className={styles.video_player} id={`user-${uid}`}&gt;&lt;/div&gt;
      &lt;/div&gt;
    );
    // add it to players
    setPlayers((prev) =&gt; [...prev, player]);
  }, []);

  return (
    &lt;&gt;
      {console.log(&quot;This is a new render... players: &quot;,players,&quot;and videoInDisplayFrame: &quot;,videoInDisplayFrame)}
      &lt;section
        className={styles.stream__container}
      &gt;
        &lt;div
          ref={displayFrame_ref}
          id=&quot;stream__box&quot;
          className={styles.stream__box}
          onClick={hideDisplayFrame}
        &gt;
          {videoInDisplayFrame}
        &lt;/div&gt;

        &lt;div
          ref={streams__container_ref}
          className={styles.streams__container}
        &gt;
          {/* display players inside JSX */}
          {players.map((element, index) =&gt; (
            &lt;div key={index}&gt;{element}&lt;/div&gt;
          ))}
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/&gt;
  );
}

when I mount the components for the first time and then click on the only player I have to display it, I can see that my players state is an empty array, I expected it to contain the element so I can remove it and set it inside videoInDisplayFrame because useEffect should update it so the component rerenders and the state is updated before I click, I even added this button

&lt;button
  onClick={() =&gt; {
   console.log(&quot;current state... players: &quot;,players,&quot;videoInDisplayFrame:&quot;,videoInDisplayFrame);
  }}
 &gt;
current state
&lt;/button&gt;

to be able to see the state at any moment and the output was confusing :
我的状态为空,当我尝试从函数中访问它时?

as you can see, even when I clicked on the button to see the state before expandVideoFrame and after it and it is not empty event when I click to run hideDisplayFrame after this, players is not empty so why it is when expandVideoFrame runs?.

答案1

得分: 1

这是因为你在其中使用了函数expandVideoFrame来存储HTML。

因此,当它运行第一个useEffect时,它会存储该函数而没有任何播放器。这就是为什么你总是得到一个空数组。

你必须只存储你想要的数据,并在组件的返回中渲染HTML。

英文:

It is because you store the HTML with the function expandVideoFrame in it.

Thus when it runs the first useEffect it stores the function without any players. That's why you always have an empty array.

You have to store only the data you want and render the HTML in the return of your component.

huangapple
  • 本文由 发表于 2023年6月9日 06:59:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定