如何在反应中呈现特定元素的弹出窗口?

How to render popup for specific element in react?

我有一个项目列表,对于每个项目 (.item-wrapper),我都想获得一个带有唯一 videoId 的视频弹出窗口。

我已经为此准备了 videoPopup 组件,但是对于每个项目,我都得到了 'elements' 数组的最后一个 'videoId'(每个项目都具有相同的 videoId)。

另一方面,当我不使用 PopupVideo 组件而只是循环遍历项目 iframe 时,我获得了特定项目的正确 ID - 这仅用于测试目的。 (注释掉的行)

我是 React 的超级新手,所以我知道这个问题可能也很容易解决。

谢谢!

显示项目的代码:


class Training extends Component {
  constructor(props) {
    super(props);
    this.state = {
      popupShowed: false
    };
  }

  togglePopup = event => {
    this.setState({
      popupShowed: !this.state.popupShowed
    });
  };

  onClosePopup = () => {
    this.togglePopup();
  };

  content = () => {
    const elements = ["76979871", "72675442", "337398380"];

    const items = [];

    for (const [index, value] of elements.entries()) {
      items.push(
        <div className="item-wrapper d-flex mb-4" key={index}>
          <div className="item-col training-num text-white font-weight-normal d-flex align-items-center justify-content-center">
            <span>{index < 10 ? "0" + index : index}</span>
          </div>
          <div className="item-col desc-col">
            <h3 className="text-white title font-weight-normal">
              Dlaczego warto?
            </h3>
            <div className="text-wrapper training-desc text-white">
              <p>
                Dowiesz się dlaczego Social Media Ninja to Zawód Przyszłości.
                Dostaniesz wiedzę na temat oferowania i briefowania klientów i
                dowiesz się jak zarabiać na social mediach.
              </p>
            </div>
          </div>
          <div className="item-col text-white time-col">
            <div className="inside-wrapper">
              <p className="text-nowrap">
                <strong>Czas trwania:</strong> 2:25:00
                <br />
                <strong>Twój postęp:</strong> 90%
              </p>
            </div>
          </div>
          <div className="item-col play-col d-flex align-items-center justify-content-center d-flex align-items-center justify-content-center">
            <div className="play-wrapper" onClick={this.togglePopup}>
              <svg
                enableBackground="new 0 0 60.001 60.001"
                viewBox="0 0 60.001 60.001"
                xmlns="http://www.w3.org/2000/svg"
                className="play-button"
              >
                <path d="m59.895 58.531-29-58c-.34-.678-1.449-.678-1.789 0l-29 58c-.155.31-.139.678.044.973.182.294.504.474.85.474h58c.347 0 .668-.18.851-.474.182-.295.199-.663.044-.973zm-57.277-.553 27.382-54.764 27.382 54.764z" />
              </svg>
              <span className="text-white mt-2 d-inline-block">zobacz</span>
              {/* <iframe src={'https://player.vimeo.com/video/' + value} width="500" height="600" frameBorder="0" allowFullScreen mozallowfullscreen="true" allowFullScreen></iframe> */}
            </div>
          </div>
          {this.state.popupShowed ? (
            <PopupVideo videoId={value} closePopup={this.onClosePopup} />
          ) : null}
        </div>
      );
    }

    return <div className="list-wrapper">{items}</div>;
  };
  render() {
    return <Layout content={this.content()} />;
  }
}

export default Training;

显示popupVideo的代码:

class PopupVideo extends Component {
  componentDidMount = () => {
    var iframe = document.querySelector("iframe");
    var player = new Player(iframe);

    player.on("play", function() {
      console.log("played the video!");
    });
  };

  render() {
    return (
      <div className="popup video-popup">
        <div className="popup-inner d-flex align-items-center d-flex justify-content-center">
          <div className="video">
            <span
              onClick={this.props.closePopup}
              className="close-video d-flex align-items-center justify-content-center"
            >
              <img
                src="https://rahimblak.com/images/video-close.png"
                alt="close video"
              />
            </span>
            <div className="embed-container">
              <iframe
                src={
                  "https://player.vimeo.com/video/" +
                  this.props.videoId +
                  "?api=1&amp;autoplay=0#t=0"
                }
                title="Nazwa szkolenia"
                frameBorder="0"
                allowFullScreen
                mozallowfullscreen="true"
                allowFullScreen
              ></iframe>
            </div>
            <div className="video-nav">
              <div className="video-progress"></div>
              <div className="d-flex align-items-center py-4">
                <div className="play">
                  <span className="play-video"></span>
                </div>
                <div className="stop">
                  <span className="stop-video"></span>
                </div>
                <div className="volume">
                  <span className="volume-video"></span>
                </div>
                <div className="time">00:00 / 05:50</div>
                <div className="break"></div>
                <div className="title">
                  <h4>
                    <strong className="mr-3 pr-3">01</strong>Dlaczego warto ?
                  </h4>
                </div>
                <div className="button">
                  <button className="btn btn-secondary d-flex justify-content-center text-uppercase text-light font-weight-bold px-4">
                    Zobacz następny
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default PopupVideo;

我在控制台中没有任何错误消息。

好的,我简化了组件以向您展示处理此类问题的良好模式。

首先创建一个VideoContainer来容纳state中的所有videoIds

我们将 return 一个包含 Video 个组件的数组,并将 videoId 作为 props 传递给每个组件。

这个容器将负责只向其他组件提供数据

class VideoContainer extends Component {
  state = {
    videoIds: ["76979871", "72675442", "337398380"]
  };

  renderVideo = videoId => <Video key={videoId} videoId={videoId} />

  render() {
    const { videoIds } = this.state;
    return videoIds.map(this.renderVideo);
  }
}

然后创建一个 Video 组件,它将在 state 中包含 popupShowed 并且仅当 popupShowed 为 [=23] 时才会包含 PopupVideo 组件=] 使用 && 传入 videoIdtogglePopup 处理程序作为 props.

现在每个 Video 都是一个独立的组件,其中包含 state 用于显示 PopupVideo

class Video extends Component {
  state = {
    popupShowed: false
  };

  togglePopup = () => {
    this.setState(prevState => ({
      popupShowed: !prevState.popupShowed
    }));
  };

  render() {
    const { popupShowed } = this.state;
    const { videoId } = this.props;

    return (
      <div className="item-wrapper d-flex mb-4">
        <button onClick={this.togglePopup}>Show Popup</button>
        {popupShowed && (
          <PopupVideo videoId={videoId} closePopup={this.togglePopup} />
        )}
      </div>
    );
  }
}

最后 PopupVideo

const PopupVideo = ({ videoId, closePopup }) => (
  <div className="popup video-popup">
    <span onClick={closePopup}>
      <img
        src="https://rahimblak.com/images/video-close.png"
        alt="close video"
      />
    </span>
    <div className="embed-container">
      <iframe
        src={
          "https://player.vimeo.com/video/" +
          videoId +
          "?api=1&amp;autoplay=0#t=0"
        }
        title="Nazwa szkolenia"
        frameBorder="0"
        allowFullScreen
        mozallowfullscreen="true"
      />
    </div>
  </div>
);

sandbox