【问题标题】:State JSX component not updating状态 JSX 组件未更新
【发布时间】:2020-10-14 18:40:03
【问题描述】:

我有一个使用文件选择器的音频组件,在它的 onChange 事件上,状态更新并重新加载音频组件。

fileLoaded = (event) => {

   const url = URL.createObjectURL(event.target.files[0]);

   let react_player = (
     <AudioPlayer url={url} name={event.target.files[0].name} />
   );

   this.setState({ reactPlayer: react_player });

   event.preventDefault();
 };

render() {

   return (
     <div>
       <form onSubmit={this.submitAudioFile}>
         <Button
           className="Button"
           size="large"
           variant="contained"
           component="label"
           startIcon={<CloudUploadIcon />}
         >
           Upload File
           <input
             accept="audio/*"
             type="file"
             onChange={this.fileLoaded}
             style={{ display: "none" }}
           />
         </Button>
       </form>
       {this.state.reactPlayer}
     </div>
   );
 } 

因此,每次更改文件时,reactPlayer 组件都应该从状态中重新渲染。但这并没有发生,即使在触发 onChange 事件之后,加载到 reactPlayer 的文件仍然保持不变。

这是AudioPlayer 组件。

  constructor(props) {
    super();
    this.audioRef = React.createRef();
  }

  componentDidMount() {
    this.setState({ audioSource: this.props.url, name: this.props.name });
    console.log(this.props.name);
  }

  state = {
    playing: false,
    source: null,
    currentTime: 0,
    totalTime: 0,
    audioSource: "",
    name: "",
  };

  playOrPauseButton = () => {
    // console.log("CALLED");

    // const styleJson = { color: "#000", fontSize: "50" };

    if (!this.state.playing) {
      return (
        <PlayCircleFilledIcon
          //   style={styleJson}
          className="playPauseButtonHover"
          onClick={this.playOrPause}
        />
      );
    } else {
      return (
        <PauseCircleFilledIcon
          className="playPauseButtonHover"
          //   style={styleJson}
          onClick={this.playOrPause}
        />
      );
    }
  };

  playOrPause = () => {
    // console.log("Hello");
    if (this.state.playing) {
      this.audioRef.current.pause();
      console.log("pause");
    } else {
      this.audioRef.current.play();
      console.log("play");
    }
    const prevPlayingState = this.state.playing;
    this.setState({ playing: !prevPlayingState });
  };

  audioIsPlaying = (e) => {
    this.setState({ currentTime: Math.floor(e.target.currentTime) });
    this.setState({ duration: Math.floor(e.target.duration) });

    // console.log(this.state.currentTime + ":" + this.state.duration);
  };

  audioEnded = (e) => {
    console.log("ended");
    this.setState({ playing: false, currentTime: 0 });
  };

  audioWasLoaded = (e) => {
    this.setState({ duration: Math.floor(e.target.duration) });
    // let x = e.target.src;
  };

  render() {
    let x = this.playOrPauseButton();
    // this.getAudioLength();

    return (
      <div>
        <LinearProgress
          className="top"
          variant="determinate"
          value={(this.state.currentTime * 100) / this.state.duration}
        />
        <div className={styles.audioPlayerDiv}>
          {x}
          <div>
            <p style={{ textAlign: "center" }}>
              {this.state.currentTime}/{this.state.duration}
            </p>

            <p style={{ fontWeight: "bold" }}>{this.state.name}</p>
          </div>

          <audio
            onLoadedMetadata={(event) => this.audioWasLoaded(event)}
            onEnded={(event) => this.audioEnded(event)}
            onTimeUpdate={(event) => this.audioIsPlaying(event)}
            src={this.state.audioSource}
            ref={this.audioRef}
          />

          <NoteAddIcon className="playPauseButtonHover"></NoteAddIcon>
          {/* <button style={{ alignItems: "left" }}>take note</button> */}
        </div>
      </div>
    );
  }
}

export default AudioPlayer;```

【问题讨论】:

    标签: javascript reactjs html5-audio react-state


    【解决方案1】:

    找到了解决方案。诀窍是传递 props 并篡改 AudioPlayer 组件中的状态。

              <audio
                onLoadedMetadata={(event) => this.audioWasLoaded(event)}
                onEnded={(event) => this.audioEnded(event)}
                onTimeUpdate={(event) => this.audioIsPlaying(event)}
                src={this.props.url}
                ref={this.audioRef}
              />
    

    只需将音频标签的 src 连接到从父组件传递的道具上,一切正常。

    【讨论】:

      【解决方案2】:

      Don't store jsx in state

      只需在状态中存储 url 的名称并渲染 jsx。

      像这样

      ...
      state = {
          url: '',
          name: ''
      }
      fileLoaded = (event) => {
      
          const url = URL.createObjectURL(event.target.files[0]);
       
          let react_player = {
              url,
              name: event.target.files[0].name
          };
       
          this.setState({ reactPlayer: react_player });
       
          event.preventDefault();
        };
       
       render() {
       
          return (
            <div>
              <form onSubmit={this.submitAudioFile}>
                <Button
                  className="Button"
                  size="large"
                  variant="contained"
                  component="label"
                  startIcon={<CloudUploadIcon />}
                >
                  Upload File
                  <input
                    accept="audio/*"
                    type="file"
                    onChange={this.fileLoaded}
                    style={{ display: "none" }}
                  />
                </Button>
              </form>
              {/* {this.state.reactPlayer} */}
              {this.state.url && <AudioPlayer url={this.state.url} name={this.state.name} />}
            </div>
          );
        } 
      

      【讨论】:

      • 试过你的解决方案。事件流转到fileLoaded,但它不调用AudioPlayer 组件的构造函数。我已重新连接整个状态以仅保存要传递给 AudioPlayer 的值
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-15
      • 1970-01-01
      相关资源
      最近更新 更多