我刚刚开始学习 React.js,我正在尝试解决问题。我正在创建一个简单的冥想应用程序,其中每个按钮都有一个与之链接的声音。我创建了 4 个按钮(针对每个可用的声音),当单击它时,声音就会播放。但显然,当单击其他按钮时,之前的声音会在后台继续播放。我已经安装了react-player来更好地控制它,并且我尝试使用useState找到解决方案。
这是代码:
import PropTypes from "prop-types";
import { useState } from "react";
import ReactPlayer from "react-player";
function Buttons({ soundsColor }) {
const [alternativeText, setAlternativeText] = useState(null);
const [playing, setPlaying] = useState(true);
function playSound(soundUrl) {
if (!playing) {
soundUrl.play();
} else {
setPlaying(!playing);
}
console.log("Playing sound:", soundUrl);
}
function handleText(id) {
setAlternativeText(id);
}
return (
<>
{/* Destructuring per rilevare le properties dall'oggetto */}
{soundsColor.map(({ name, color, description, sound, id }, index) => (
<button
id={`btn-${index}`}
className="p-20 relative rounded-[10px] active:scale-[0.98] transition-all 150ms ease-in "
style={{ backgroundColor: color }}
key={id}
onClick={() => {
playSound(sound);
handleText(id);
}}
>
<ReactPlayer
url={sound}
playing={playing}
width="100%"
height="100%"
/>
<div className="absolute top-20 w-3/4 left-3 text-left">
<p className="text-[#000] font-bold font-sourceSans">{name}</p>
<small className="font-sourceSans text-secondSubtext font-light ">
{alternativeText === id ? "Playing..." : description}
</small>
</div>
</button>
))}
</>
);
}
Buttons.propTypes = {
soundsColor: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number,
name: PropTypes.string,
description: PropTypes.string,
color: PropTypes.string,
sound: PropTypes.object,
})
),
};
export function SoundScapes() {
const soundsColor = [
{
id: 0,
name: "Suikinkutsu",
color: "#daff6f",
description: "Water Drip Resonance",
sound: new Audio("assets/Suikinkutsu.mp3"),
},
{
id: 1,
name: "Cicadas",
color: "#A8AEEF",
description: "Insect Chorus",
sound: new Audio("./assets/Cicadas.mp3"),
},
{
id: 2,
name: "Temple Bells",
color: "#A8AEEF",
description: "Waterfall Roar",
sound: new Audio("./assets/TempleBellSound.mp3"),
},
{
id: 3,
name: "Shomyo Falls",
color: "#daff6f",
description: "Bell Resonance",
sound: new Audio("./assets/Waterfall.mp3"),
},
];
return (
<div className="grid grid-cols-2 grid-rows-2 gap-3 p-6 mt-8">
<Buttons soundsColor={soundsColor} />
</div>
);
}
我想创建一个:
const [playing,setPlaying] = useState(true)
但我想我必须将它“附加”到 playSound() 函数,这使得单击按钮时播放声音,并添加一段代码来在按下另一个按钮时更改状态,但这就是我的位置我被卡住了。
如果我的方法是错误的,我将不胜感激您帮助理解这一点。非常感谢你
首先,我真的建议你使用 TypeScript,而不是修改
PropTypes
。学习曲线并没有那么陡峭,它会在未来为你省去很多麻烦。
其次,我建议您在可以避免的情况下不要修改现有原型。几乎(?)总是有其他选择,否则事情就会变得混乱。
好吧,就以你的例子为例。您使用
useState
的预感是正确的,但您需要
memoize
声音,这样它们就不会一直重新创建。以下是有关如何创建、播放和停止声音的草图。我省略了按钮逻辑,因为您的问题看起来您知道如何处理这些问题。export const Buttons: React.FC = () => {
// There are many ways to get a structure from id to sound. You could even use a plain object of type { [key:number]: ReturnType<typeof getSoundScapes>[number]>}
// The important thing is that you create this list with useMemo and an empty dependency array, so on subsequent renderings new sounds will be created
const soundScapes = useMemo(() => getSoundScapes().reduce(
(prev, curr) => prev.set(curr.id, curr), new Map<number, ReturnType<typeof getSoundScapes>[number]>,
), []);
// Here we store whether (and which) sound is playing currently
const [playing, setPlaying] = React.useState<number|null>(null);
// onClick handler is for your button to use. It will stop the currently playing sound (if any) and start the new one.
// Additionally, the new sound will be stored as the one currently being played.
const onClick = (idToPlay:number)=>{
if (playing != null){
const currentSound = soundScapes.get(playing);
if (currentSound != null){
// this only works b/c the songs are memoized - otherwise you would try to pause a new Sound instance which isn't even running
currentSound.sound.pause();
currentSound.sound.currentTime=0;
}
}
const toPlay =soundScapes.get(idToPlay);
if (toPlay != null){
toPlay.sound.play();
setPlaying(idToPlay);
}
}
return Array.of(soundScapes.values()).map( ... create the buttons similar to your example)
};
我使用了 TypeScript b/c,这对我来说更容易 - 你只需删除纯 JavaScript 代码的类型声明即可。
因此,有两个要点:
memoize
Sound
对象,您甚至无法停止当前正在运行的对象。只需使用 id 来引用播放的声音 - 更容易调试(b/c 您可以通过检查 number