【问题标题】:How do you update an image source from a variable state?如何从可变状态更新图像源?
【发布时间】:2021-07-06 23:10:43
【问题描述】:

基本上,我试图在每次单击按钮时在按钮内的暂停/播放图标之间更改图像源。我的问题不在于将状态传递给源,而是在更新状态时更改源。

const playButton = "/images/play-button.svg";
const pauseButton = "/images/pause-button.svg";

我有一个数据源,我们将调用data,它是一个包含音频文件的数组,我将它映射到一个包含音频对象、播放状态和按钮 URL 的并行数组,类似于:

const [audioArray, setAudioArray] = useState([]);
useEffect( () => {

var audioArrayHolder = [];
data.map( item => {
            var audioItem = new Audio(item.audioURL);
            audioArrayHolder.push({
                                   audio: audioItem,
                                   playState: false,
                                   button: playButton
                                 })
});
setAudioArray(audioArrayHolder);
}, [data]);

现在可以将其加载到一组组件中,每个组件都有一个处理其音频播放的按钮:

function handlePausePlay(someIndex) {
     var audioArrayCopy = audioArray;
     var audioArrayObj = audioArray(someIndex);

     if (audioArrayObj.playState) {
        audioArrayObj.audio.pause();
        audioArrayObj.playState = false;
        audioArrayObj.button = playButton;

 } else {
        audioArrayObj.audio.play();
        audioArrayObj.playState = true;
        audioArrayObj.button = pauseButton;
 }

     audioArrayCopy[someIndex] = audioArrayObj;
     setAudioArray(audioArrayCopy);
}

data.map( (item, index) => {

<div>
   <ExampleComponent songName={data.name} songArtists={data.artists}/>

   <button onClick={handlePausePlay(index)}>
      <img src={audioArray[index].button} alt="Pause/Play Button"/>
   </button>
</div>

});

这会通过一个功能性暂停/播放按钮很好地加载所有组件,该按钮根本不会改变图像。每次按下按钮时,handlePausePlay 会在该索引处更新audioArray 的状态,并成功更改audioArray[index].button 属性,但src 已经渲染,因此图像卡在playButton,默认。

我尝试将图像作为一个单独的组件并将src 作为道具传递,并通过按下按钮将索引保存到名为currentIndex 的状态常量中,并将其传递到源中(即&lt;img src={audioArray[currentIndex].button} ... /&gt; ) 以及介于两者之间的许多愚蠢的想法。

这应该是一个微不足道的问题,但老实说,我作为一个新手在 2 天的大部分时间里都感到困惑。任何帮助表示赞赏。

【问题讨论】:

  • audioArray[index].button 的内容是什么? “播放按钮”?
  • 是的,在问题的顶部,它被定义为图像的 url。它的功能还在于图像成功显示 url,只是在 .button 属性设置为 pauseButton 时不会重新渲染
  • 可以把handlePausePlay的代码加到帖子里吗?
  • 当然,我认为这不是最干净的方法,但哈哈。它确实有效,因为音频开始/停止,这意味着 .playState 属性正在更新(并且 .button 也是如此)

标签: javascript reactjs state


【解决方案1】:

我有一个可行的解决方案

创建新的状态加载

const [loading, setLoading] = useState(false);

然后在 handlePausePlay 中设置 Loading 为 true 像这样:

function handlePausePlay(someIndex) {
selLoading(true)
     var audioArrayCopy = audioArray;
     var audioArrayObj = audioArray(someIndex);

 if (audioArrayObj.playState) {
    audioArrayObj.audio.pause();
    audioArrayObj.playState = false;
    audioArrayObj.button = playButton;

 } else {
        audioArrayObj.audio.play();
        audioArrayObj.playState = true;
        audioArrayObj.button = pauseButton;
 }
     audioArrayCopy[someIndex] = audioArrayObj;
     setAudioArray(audioArrayCopy);

setTimeout(()=>setLoading(false),1000)
    }

然后使用 img 标签执行此操作:

<div>


 <ExampleComponent songName={data.name} songArtists={data.artists}/>

   <button onClick={handlePausePlay(index)}>
      !loading && <img src={audioArray[index].button} alt="Pause/Play Button"/>
   </button>
</div>

【讨论】:

    【解决方案2】:

    好的,让我们看看。

    我发现了一些我们需要注意的事情。

    首先:

    var audioArrayObj = audioArray(someIndex);
    

    audioArray 不是函数是数组,因此要访问您需要的值,您必须使用 []

    var audioArrayObj = audioArray[someIndex];
    

    其次,我建议只使用一个数组来显示您的数据,而不是像您在return 那样混合使用两个数组。

    data.map( (item, index) => {
    
    <div>
       <ExampleComponent songName={data.name} songArtists={data.artists}/>
    
       <button onClick={handlePausePlay(index)}>
          <img src={audioArray[index].button} alt="Pause/Play Button"/>
       </button>
    </div>
    
    });
    

    在这段代码中,我发现您的 onClick 函数不是箭头函数...这将导致在渲染时执行。因此,它不会像您预期的那样工作。

    onClick={handlePausePlay(index)}
    

    正确使用方法:

    onClick={()=>handlePausePlay(index)}
    

    最后,我用工作代码创建了一个 sn-p。 只有一个数组来显示数据,我将audioArraydata 值混合在一起,并将其混合在useEffect 上。 我使用 span 来模拟图像,并将 altButton 文本添加为​​每个对象的变量。 我删除 new Audio 代码只是为了使代码 sn-p 正常工作。 而在handlePausePlay函数的最后,我使用spread operator让useState意识到它有一个新的值。

    setAudioArray([...audioArrayCopy]);
    

    代码sn-p:

    // Get a hook function
    const {useState, useEffect} = React;
    const playButton = "/images/play-button.svg";
    const pauseButton = "/images/pause-button.svg";
    
    const Example = () => {
    
      const [audioArray, setAudioArray] = useState([{
         playState: false,
         altText: "Play Button",
         button: playButton
      },{
         playState: false,
         altText: "Play Button",
         button: playButton
      },{
         playState: false,
         altText: "Play Button",
         button: playButton
      }
      ]);
      const [data, setData] = useState([{
        name: "Song1", 
        artist: "Artist1"
      },{
        name: "Song2", 
        artist: "Artist2"
      },{
        name: "Song3", 
        artist: "Artist3"
      }]);
      
        useEffect( () => {
          var audioArrayHolder = [];
          data.map( item => {
            audioArrayHolder.push({
                                   name: item.name, 
                                   artist: item.artist,
                                   playState: false,
                                   altText: "Play Button",
                                   button: playButton
                                 })
          });
          setAudioArray(audioArrayHolder);
        }, [data]);
      
      
      const handlePausePlay = (someIndex) => {
           var audioArrayCopy = audioArray;
           var audioArrayObj = audioArray[someIndex];
    
           if (audioArrayObj.playState) {
              audioArrayObj.playState = false;
              audioArrayObj.altText = "Play Button",
              audioArrayObj.button = playButton;
         } else {
                audioArrayObj.playState = true;
                audioArrayObj.altText = "Pause Button",
                audioArrayObj.button = pauseButton;
         }
    
           audioArrayCopy[someIndex] = audioArrayObj;
           setAudioArray([...audioArrayCopy]);
      }
    
      return (
        <div>
          {audioArray.map( (item, index) => {
          return <div>
             <span> Playing {item.name} - ({item.artist}) </span>
    
             <button onClick={()=>handlePausePlay(index)}>
                {/*<img src={item.button} alt="Pause/Play Button"/>*/}
                <span> src={item.button} alt={item.altText}</span>
             </button>
          </div>
          })}
        </div>
      );
    };
    
    
    
    
    // Render it
    ReactDOM.render(
      <Example title="Example using Hooks:" />,
      document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

    【讨论】:

    • 哇这工作!我认为扩展运算符使用和数组组合的组合做到了。我不知道为什么我没有想到使用一个数组,我猜你在写了这么多次之后我得到了隧道视觉。跨度更改没有成功,因为“playButton”和“pauseButton”只是字符串,所以它在按钮中显示了一个文本块,但作为图像重新渲染就可以了。添加回 .play() 并且它是完美的。很抱歉让你也修正了错误,我手动写出了问题的代码以简化问题,我想我犯了一些错别字。
    • 很高兴它对您有所帮助!问候
    猜你喜欢
    • 2022-01-10
    • 2020-09-23
    • 1970-01-01
    • 2016-11-10
    • 2019-01-10
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多