0

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

问题:

  1. 我不确定如何重写this.tick bind方法AudioAnalyser
  2. 在功能组件中使用标签写入canvas元素。AudioVisualiserref
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;
4

1 回答 1

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 };

让我知道这是否对您有帮助,或者您是否需要对某些代码片段进行解释。

于 2020-01-15T11:04:17.587 回答