reactjs React:从另一个组件管理组件状态的最佳方法是什么?

fkvaft9z  于 2023-02-15  发布在  React
关注(0)|答案(1)|浏览(199)

我正在React中开发一个特雷门的软件仿真。我希望使用用户的网络摄像头来跟踪手,然后可以用来控制合成器(WebAudio API)。我只想澄清一下实现我的组件的最佳方式。
我有一个视频组件和一个合成器组件。当然,从视频输出的恒定数据流将用于一致地更改合成器中的状态...我有[frequency,setFrequency]和[volume,setVolume]作为“synthesizer”函数React组件中的useStates()。
要实现这一点,构建组件的最佳方法是什么?数据应该作为 prop 传递到合成器中吗?或者有更合适的方法来实现这一点吗?简单地将它们组合成一个不断重新呈现的组件是否更好?
谢谢!

//Perhaps data passed in as props?
export const Synthesizer = ({ freq, vol }) => {
    //Changed with a slider
    const [wavetype, setWavetype] = useState(0);

    //CHANGED BY VIDEO DATA
    const [volume, setVolume] = useState(1);

    //CHANGED BY VIDEO DATA
    const [frequency, setFrequency] = useState(100);
    
    useEffect(() => {
        osc.type = waveforms[wavetype];
    }, [wavetype]);

    useEffect(() => {
        osc.frequency.value = frequency;
    }, [frequency]);

    useEffect(() => {
        gain.gain.value = volume;
    }, [volume]);

    return( //return code here... );
jdgnovmf

jdgnovmf1#

有几种方法可以做到这一点。你可以像代码一样将 prop 传递到合成器组件中。或者你可以使用Redux或Context API这样的状态管理工具,这样你就可以在整个应用中共享状态,并在任何组件中访问它。
一般来说,不建议将两个组件组合在一起,让一个组件不断地重新渲染,这会降低性能。
下面是您可以使用不同方法实现它的方法:

选项1:将视频数据作为 prop 传递

我们有一个包含Video和Synthesizer组件的父组件,它将 prop 传递给Synthesizer组件,后者使用数据更新其状态变量。

import React, { useState } from 'react';
import Video from './Video';
import Synthesizer from './Synthesizer';

function App() {
  const [videoData, setVideoData] = useState({
    volume: 1,
    frequency: 100,
  });

  // Update videoData state when video data changes
  function handleVideoDataChange(newVideoData) {
    setVideoData(newVideoData);
  }

  return (
    <div>
      <Video onVideoDataChange={handleVideoDataChange} />
      <Synthesizer volume={videoData.volume} frequency={videoData.frequency} />
    </div>
  );
}
import React, { useState, useEffect } from 'react';

function Synthesizer(props) {
  const [wavetype, setWavetype] = useState(0);
  const [volume, setVolume] = useState(props.volume);
  const [frequency, setFrequency] = useState(props.frequency);

  useEffect(() => {
    osc.type = waveforms[wavetype];
  }, [wavetype]);

  useEffect(() => {
    osc.frequency.value = frequency;
  }, [frequency]);

  useEffect(() => {
    gain.gain.value = volume;
  }, [volume]);

  return (
    // Synthesizer UI code here
  );
}

选项2:使用上下文API

视频组件用新的视频数据更新共享状态对象,这触发合成器组件用更新的状态重新呈现。

import React, { useState, useContext } from 'react';
import { VideoDataContext } from './VideoDataContext';

function Video() {
  const [videoData, setVideoData] = useContext(VideoDataContext);

  // Update shared state object with new video data
  function handleVideoDataChange(newVideoData) {
    setVideoData(newVideoData);
  }

  return (
    // Video component code here
  );
}

Synthesizer组件可以通过useContext钩子访问共享状态对象,并使用它来更新其状态变量:

import { VideoDataContext } from './VideoDataContext';

function Synthesizer() {
  const [wavetype, setWavetype] = useState(0);
  const [volume, setVolume] = useState(1);
  const [frequency, setFrequency] = useState(100);
  const [videoData] = useContext(VideoDataContext);

  // Update state variables with video data from shared state object
  useEffect(() => {
    setVolume(videoData.volume);
    setFrequency(videoData.frequency);
  }, [videoData]);

  useEffect(() => {
    osc.type = waveforms[wavetype];
  }, [wavetype]);

  useEffect(() => {
    osc.frequency.value = frequency;
  }, [frequency]);

  useEffect(() => {
    gain.gain.value = volume;
  }, [volume]);

  return (
    // Synthesizer UI code here
  );
}

选项3:使用Redux

Redux会有更多的样板文件,通常不建议用于小型应用。首先,你需要创建一个动作类型和动作创建器来更新视频数据:

export const UPDATE_VIDEO_DATA = 'UPDATE_VIDEO_DATA';

export function updateVideoData(newData) {
  return { type: UPDATE_VIDEO_DATA, payload: newData };
}

然后,您应该创建一个reducer函数来处理UPDATE_VIDEO_DATA操作并更新状态中的视频数据:

const initialState = {
  videoData: {
    volume: 1,
    frequency: 100,
  },
};

function videoReducer(state = initialState, action) {
  switch (action.type) {
    case UPDATE_VIDEO_DATA:
      return { ...state, videoData: action.payload };
    default:
      return state;
  }
}

您还需要使用videoReducer创建一个存储:

import { createStore } from 'redux';
import videoReducer from './reducers/videoReducer';

const store = createStore(videoReducer);

在Video组件中,您可以调度updateVideoData操作以更新处于以下状态的视频数据:

import React from 'react';
import { useDispatch } from 'react-redux';
import { updateVideoData } from '../actions/videoActions';

function Video() {
  const dispatch = useDispatch();

  // Update video data in the state when it changes
  function handleVideoDataChange(newVideoData) {
    dispatch(updateVideoData(newVideoData));
  }

  return (
    // Video component code here
  );
}

在合成器组件中,可以使用useSelector挂钩访问状态中的视频数据并更新组件的状态变量:

import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';

function Synthesizer() {
  const [wavetype, setWavetype] = useState(0);
  const [volume, setVolume] = useState(1);
  const [frequency, setFrequency] = useState(100);
  const videoData = useSelector(state => state.videoData);

  useEffect(() => {
    setVolume(videoData.volume);
    setFrequency(videoData.frequency);
  }, [videoData]);

  useEffect(() => {
    osc.type = waveforms[wavetype];
  }, [wavetype]);

  useEffect(() => {
    osc.frequency.value = frequency;
  }, [frequency]);

  useEffect(() => {
    gain.gain.value = volume;
  }, [volume]);

  return (
    // Synthesizer UI code here
  );
}

通过这种设置,视频组件会分派一个动作来更新状态中的视频数据,这会触发合成器组件使用更新后的状态数据进行重新渲染。正如您所看到的,如果您的应用将成为一个大应用,这将不是一种方法。最佳方法将取决于您的应用的特定需求以及视频组件和合成器组件之间数据流的复杂性。

相关问题