简体   繁体   中英

How can I use a loop to make this React component more DRY?

I'm trying to make an audio mixer using the web audio api. I'm having trouble figuring out how to name the refs. How can I create this component without hard coding every track?

import React, { useState, useEffect, useRef } from "react";
import "./App.css";
import { initialTracks } from "./initialTracks";

function App() {
  const [tracks, setTracks] = useState(initialTracks);
  const [isPlaying, setIsPlaying] = useState(true);
  const trackRef0 = useRef();
  const trackRef1 = useRef();
  const trackRef2 = useRef();
  const trackRef3 = useRef();
  const trackRef4 = useRef();
  const trackRef5 = useRef();
  const trackRef6 = useRef();
  const trackRef7 = useRef();
  const trackRef8 = useRef();
  const trackRef9 = useRef();
  const trackRef10 = useRef();
  const trackRef11 = useRef();

  console.log("length", tracks.length);

  useEffect(() => {
    const audioElement0 = trackRef0.current;
    const audioElement1 = trackRef1.current;
    const audioElement2 = trackRef2.current;
    const audioElement3 = trackRef3.current;
    const audioElement4 = trackRef4.current;
    const audioElement5 = trackRef5.current;
    const audioElement6 = trackRef6.current;
    const audioElement7 = trackRef7.current;
    const audioElement8 = trackRef8.current;
    const audioElement9 = trackRef9.current;
    const audioElement10 = trackRef10.current;
    const audioElement11 = trackRef11.current;
    const AudioContext = window.AudioContext || window.webkitAudioContext;
    const audioContext = new AudioContext();

    const track0 = audioContext.createMediaElementSource(audioElement0);
    const track1 = audioContext.createMediaElementSource(audioElement1);
    const track2 = audioContext.createMediaElementSource(audioElement2);
    const track3 = audioContext.createMediaElementSource(audioElement3);
    const track4 = audioContext.createMediaElementSource(audioElement4);
    const track5 = audioContext.createMediaElementSource(audioElement5);
    const track6 = audioContext.createMediaElementSource(audioElement6);
    const track7 = audioContext.createMediaElementSource(audioElement7);
    const track8 = audioContext.createMediaElementSource(audioElement8);
    const track9 = audioContext.createMediaElementSource(audioElement9);
    const track10 = audioContext.createMediaElementSource(audioElement10);
    const track11 = audioContext.createMediaElementSource(audioElement11);

    track0.connect(audioContext.destination);
    track1.connect(audioContext.destination);
    track2.connect(audioContext.destination);
    track3.connect(audioContext.destination);
    track4.connect(audioContext.destination);
    track5.connect(audioContext.destination);
    track6.connect(audioContext.destination);
    track7.connect(audioContext.destination);
    track8.connect(audioContext.destination);
    track9.connect(audioContext.destination);
    track10.connect(audioContext.destination);
    track11.connect(audioContext.destination);
    audioContext.resume();
  }, []);

  useEffect(() => {
    const audioElement0 = trackRef0.current;
    const audioElement1 = trackRef1.current;
    const audioElement2 = trackRef2.current;
    const audioElement3 = trackRef3.current;
    const audioElement4 = trackRef4.current;
    const audioElement5 = trackRef5.current;
    const audioElement6 = trackRef6.current;
    const audioElement7 = trackRef7.current;
    const audioElement8 = trackRef8.current;
    const audioElement9 = trackRef9.current;
    const audioElement10 = trackRef10.current;
    const audioElement11 = trackRef11.current;

    if (isPlaying) {
      audioElement0.pause();
      audioElement1.pause();
      audioElement2.pause();
      audioElement3.pause();
      audioElement4.pause();
      audioElement5.pause();
      audioElement6.pause();
      audioElement7.pause();
      audioElement8.pause();
      audioElement9.pause();
      audioElement10.pause();
      audioElement11.pause();
    } else {
      audioElement0.play();
      audioElement1.play();
      audioElement2.play();
      audioElement3.play();
      audioElement4.play();
      audioElement5.play();
      audioElement6.play();
      audioElement7.play();
      audioElement8.play();
      audioElement9.play();
      audioElement10.play();
      audioElement11.play();
    }
  }, [isPlaying]);

  const channels = tracks.map((track, i) => {
    return (
      <div key={track.path}>
        <audio ref={trackRef0} src={tracks[0].path}></audio>
        <audio ref={trackRef1} src={tracks[1].path}></audio>
        <audio ref={trackRef2} src={tracks[2].path}></audio>
        <audio ref={trackRef3} src={tracks[3].path}></audio>
        <audio ref={trackRef4} src={tracks[4].path}></audio>
        <audio ref={trackRef5} src={tracks[5].path}></audio>
        <audio ref={trackRef6} src={tracks[6].path}></audio>
        <audio ref={trackRef7} src={tracks[7].path}></audio>
        <audio ref={trackRef8} src={tracks[8].path}></audio>
        <audio ref={trackRef9} src={tracks[9].path}></audio>
        <audio ref={trackRef10} src={tracks[10].path}></audio>
        <audio ref={trackRef11} src={tracks[11].path}></audio>
      </div>
    );
  });
  console.log("channels", channels);

  return (
    <div>
      <h1>Audio Mixer</h1>
      <button onClick={() => setIsPlaying(!isPlaying)}>play</button>
      {channels}
    </div>
  );
}

export default App;

Hi. I'm trying to make an audio mixer using the web audio api. I'm having trouble figuring out how to name the refs. How can I create this component without hard coding every track?

You only need one ref, the container, and then you can access each child with .children . Something along the lines of:

function App() {
    const [tracks, setTracks] = useState(initialTracks);
    const [isPlaying, setIsPlaying] = useState(true);
    const tracksContainerRef = useRef();

    useEffect(() => {
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        for (const audio of tracksContainerRef.current.children) {
            audioContext.createMediaElementSource(audio).connect(audioContext.destination);
        }
        audioContext.resume();
    }, []);
    useEffect(() => {
        for (const audio of tracksContainerRef.current.children) {
            if (isPlaying) {
                audio.pause();
            } else {
                audio.play();
            }
        }
    }, [isPlaying]);
    return (
        <div>
            <h1>Audio Mixer</h1>
            <button onClick={() => setIsPlaying(!isPlaying)}>play</button>
            <div ref={tracksContainerRef}>
                {
                    tracks.map(({ path }) => <audio src={path} />)
                }
            </div>
        </div>
    );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM