【问题标题】:Refactor Class Component to Functional Component将类组件重构为功能组件
【发布时间】:2020-05-02 02:15:36
【问题描述】:

我正在分析一个类组件中的一些音频,然后在另一个组件中呈现音频的波形可视化。我正在努力将这些重构为带有钩子的功能组件。 StackBlitz URL

问题:

  1. 我不知道如何重写AudioAnalyser 中的this.tick bind 方法
  2. 使用功能组件中的ref 标记写入AudioVisualiser 中的canvas 元素。
class AudioAnalyser extends Component {
   constructor(props) {
      super(props);
      this.state = { audioData: new Uint8Array(0) };
      this.tick = this.tick.bind(this);
   }

   componentDidMount() {
      this.audioContext = new window.AudioContext();
      this.analyser = this.audioContext.createAnalyser();
      this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
      this.source = this.audioContext.createMediaStreamSource(this.props.audio);
      this.source.connect(this.analyser);
      this.rafId = requestAnimationFrame(this.tick);
   }

   tick() {
      this.analyser.getByteTimeDomainData(this.dataArray);
      this.setState({ audioData: this.dataArray });
      this.rafId = requestAnimationFrame(this.tick);
   }

   componentWillUnmount() {
      cancelAnimationFrame(this.rafId);
      this.analyser.disconnect();
      this.source.disconnect();
   }

   render() {
      return <AudioVisualiser audioData={this.state.audioData} />;
   }
}

export default AudioAnalyser;
class AudioVisualiser extends Component {
    constructor(props) {
        super(props);
        this.canvas = React.createRef();
    }

    componentDidUpdate() {
        this.draw();
    }

    draw() {
        const { audioData } = this.props;
        const canvas = this.canvas.current;
        const height = canvas.height;
        const width = canvas.width;
        const context = canvas.getContext('2d');
        let x = 0;
        const sliceWidth = (width * 1.0) / audioData.length;

        context.lineWidth = 2;
        context.strokeStyle = '#000000';
        context.clearRect(0, 0, width, height);

        context.beginPath();
        context.moveTo(0, height / 2);
        for (const item of audioData) {
            const y = (item / 255.0) * height;
            context.lineTo(x, y);
            x += sliceWidth;
        }
        context.lineTo(x, height / 2);
        context.stroke();
    }

    render() {
        return <canvas width="300" height="300" ref={this.canvas} />;
    }
}

export default AudioVisualiser;

【问题讨论】:

    标签: reactjs refactoring mediastream react-functional-component


    【解决方案1】:

    未经测试,但应该朝这个方向发展

    import React, { useEffect, useState } from 'react';
    
    function useAudio(audio) {
      const [analyser, setAnalyser] = useState();
      const [audioContext, setAudioContext] = useState();
      const [audioData, setAudioData] = useState();
      const [dataArray, setDataArray] = useState();
      const [rafId, setRafId] = useState();
      const [source, setSource] = useState();
    
      useEffect(() => {
        const tick = () => {
          analyser.getByteTimeDomainData(this.dataArray);
          setAudioData(dataArray);
          setRafId(requestAnimationFrame(tick));
        };
    
        setAudioContext(new window.AudioContext());
        setAnalyser(audioContext.createAnalyser());
        setDataArray(new Uint8Array(analyser.frequencyBinCount));
        setSource(audioContext.createMediaStreamSource(audio), () => {
          source.connect(analyser);
        });
        setRafId(requestAnimationFrame(tick));
    
        return () => {
          cancelAnimationFrame(rafId);
          analyser.disconnect();
          source.disconnect();
        };
      }, []);
    
      return [audioData, setAudioData];
    }
    
    function AudioAnalyser({ audio }) {
      const [audioData] = useAudio(audio);
      return <AudioVisualiser audioData={audioData} />;
    }
    
    export default AudioAnalyser;
    

    还有二等

    import React, { useEffect, useRef } from 'react';
    
    function Canvas({ audioData }) {
      const canvasRef = useRef();
      const didMountRef = useRef(false);
    
      useEffect(() => {
        const draw = () => {
          const canvas = canvasRef.current;
          const height = canvas.height;
          const width = canvas.width;
          const context = canvas.getContext('2d');
          const sliceWidth = (width * 1.0) / audioData.length;
    
          context.lineWidth = 2;
          context.strokeStyle = '#000000';
          context.clearRect(0, 0, width, height);
    
          context.beginPath();
          context.moveTo(0, height / 2);
    
          let x = 0;
          for (const item of audioData) {
            const y = (item / 255.0) * height;
            context.lineTo(x, y);
            x += sliceWidth;
          }
          context.lineTo(x, height / 2);
          context.stroke();
        };
    
        if (didMountRef.current) {
          draw();
        } else didMountRef.current = true;
      }, []);
    
      return <canvas width="300" height="300" ref={canvasRef} />;
    }
    
    export { Canvas as default };
    

    如果这对您有帮助,或者您是否需要对某些代码 sn-p 的解释,请告诉我。

    【讨论】:

      猜你喜欢
      • 2021-12-28
      • 1970-01-01
      • 2020-11-19
      • 2021-01-04
      • 2020-02-08
      • 1970-01-01
      • 2020-08-26
      • 2021-03-24
      相关资源
      最近更新 更多