【问题标题】:React Hooks useState useEffect slideshowReact Hooks useState useEffect 幻灯片
【发布时间】:2020-10-15 13:50:30
【问题描述】:

我正在尝试通过 props 将以下数据传递给 Slide.js 来制作幻灯片应用。

const SLIDES = [
    {
        title: "Today's workout plan",
        text: "We're gonna do 3 fundamental exercises."
    },
    {
        title: "First, 10 push-ups",
        text: "Do 10 reps. Remember about full range of motion. Don't rush."
    },
    {
        title: "Next, 20 squats",
        text: "Squats are important. Remember to keep your back straight."
    },
    {
        title: "Finally, 15 sit-ups",
        text: "Slightly bend your knees. Remember about full range of motion."
    },
    {
        title: "Great job!",
        text: "You made it, have a nice day and see you next time!"
    }
];

我的子组件Slide.js有如下代码

import React, { useState, useEffect } from "react";

function Slides({ slides }) {
  const [slideShow, setSlide] = useState(slides);

  useEffect(() => {
    setSlide(slideShow[0]);
    console.log("slides", slideShow[0]);
  }, []);

  return (
    <div>
      <div id="navigation" className="text-center">
        <button data-testid="button-restart" className="small outlined">
          Restart
        </button>
        <button data-testid="button-prev" className="small">
          Prev
        </button>
        <button data-testid="button-next" className="small">
          Next
        </button>
      </div>
      {slideShow.map((slide, i) => (
        <div id={i} className="card text-center">
          <h1 data-testid="title">{slide.title}</h1>
          <p data-testid="text">{slide.text}</p>
        </div>
      ))}
    </div>
  );
}

export default Slides;

我认为使用setSlide(slideShow[0]) 只会在应用程序初始加载后呈现对象数组中的第一项。但我明白了

TypeError: slideShow.map is not a function

但是当我console.log("slides", slideShow[0])我输出时

slides {title: "Today's workout plan", text: "We're gonna do 3 fundamental exercises."}

如果我将代码更改为

setSlide(slideShow.slice(0, 1));

应用程序仅显示数组中的第一个对象,但如果我 console.log("slides", slideShow),即使我认为我应该收到切片版本,我也会得到整个对象数组。

我的map 函数是否没有引用slideShow[0] 以导致错误发生?

【问题讨论】:

  • 当你setSlide(slideShow[0]) 你的slideShow 不再是一个可以被映射的数组,它是一个对象。在您提供给我们的代码中,根本没有理由使用 useEffect(或 useState)挂钩
  • React 中的状态变化是异步的。您不能在下一行 console.log 看到更改。在函数主体中记录状态
  • 我的地图函数是否没有引用 slideShow[0] 导致错误发生?,是的。在useEffect 你正在做setSlide(slideShow[0])这将是一个对象。因此,如果您使用 setSlide([{...slideShow[0]}]) 而不是 setSlide(slideShow[0]),那么它不会破坏应用程序。

标签: javascript reactjs react-hooks use-state


【解决方案1】:

这里的问题是setSlide(slideShow[0])。最初状态是用一个名为slides 的数组初始化的。但是在useEffect 中,该状态正在使用对象进行更新。所以,现在slideShow 不再是array,而是object。因此object.map 正在破坏应用程序。

  useEffect(() => {
    setSlide(slideShow[0]);
    console.log("slides", slideShow[0]);
  }, []);

以下是您正在寻找的操作类型的示例。我没有将slides 存储在我刚刚在state 中添加项目的index 并相应地更新它的状态中。

const SLIDES = [{title:"Today's workout plan",text:"We're gonna do 3 fundamental exercises."},{title:"First, 10 push-ups",text:"Do 10 reps. Remember about full range of motion. Don't rush."},{title:"Next, 20 squats",text:"Squats are important. Remember to keep your back straight."},{title:"Finally, 15 sit-ups",text:"Slightly bend your knees. Remember about full range of motion."},{title:"Great job!",text:"You made it, have a nice day and see you next time!"}];

const { useState, useEffect } = React;

function Slides({ slides }) {
  const [selectedIndex, setSelectedIndex] = useState(0);

  const previous = () => {
    if(selectedIndex !== 0) {
      setSelectedIndex(index => index-1);
    }
  }
  
  const next = () => {
    if(selectedIndex !== slides.length - 1) {
      setSelectedIndex(index => index+1);
    }
  }
  
  const restart = () => {
    setSelectedIndex(0);
  }
  
  return (
    <div>
      <div id="navigation" className="text-center">
        <button data-testid="button-restart" className="small outlined" onClick={restart}>
          Restart
        </button>
        <button data-testid="button-prev" className="small" onClick={previous}>
          Prev
        </button>
        <button data-testid="button-next" className="small" onClick={next}>
          Next
        </button>
      </div>
      <div className="card text-center">
        <h1 data-testid="title">{slides[selectedIndex].title}</h1>
        <p data-testid="text">{slides[selectedIndex].text}</p>
      </div>
    </div>
  );
}

ReactDOM.render(<Slides slides={SLIDES}/>, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>


<div id="react"></div>

注意:在这里,对于所有三个操作,我们可以只使用一个函数,为了简单起见,我创建了三个不同的函数来更新幻灯片索引。

【讨论】:

    【解决方案2】:

    错误是引用这一行slideShow.map((slide, i) =&gt; (

    问题是你的 useEffect 在你的组件渲染之后被调用,并且你将幻灯片设置为单张幻灯片slideShow[0]。然后,您继续重新渲染您的组件,并尝试映射到幻灯片,但幻灯片等于原始幻灯片变量 (slideshow[0]) 的第一项,并且您无法映射到单个幻灯片。


    您可能希望将代码编辑为更像

    function Slides({ slides }) {
      const [slideIdx, setSlide] = useState(0);
    
      const updateIndex = (val) => {
          if (val === -1){
              if (slideIdx === 0){
                  setSlide(slides.length -1)
              }else{
                  setSlide(slideIdx - 1)
              }
          }
          if (val === 1){
              if (slideIdx === slides.length - 1){
                  setSlide(0)
              }else{
                  setSlide(slideIdx + 1)
              }
          }
      }
    
      return (
        <div>
          <div id="navigation" className="text-center">
            <button onClick={() => setSlide(0)} data-testid="button-restart" className="small outlined">
              Restart
            </button>
            <button onClick={() => updateIndex(-1)} data-testid="button-prev" className="small">
              Prev
            </button>
            <button onClick={() => updateIndex(1)} data-testid="button-next" className="small">
              Next
            </button>
          </div>
            <div id="Whatyouwant" className="card text-center">
              <h1 data-testid="title">{slides[slideIdx].title}</h1>
              <p data-testid="text">{slides[slideIdx].text}</p>
            </div>
        </div>
      );
    }
    

    Here's an answer where I tried to implement something similar

    【讨论】:

    • 我尝试实施您的解决方案,但我得到了TypeError: Cannot read property 'title' of undefined
    • @ElijahLee 我更新了一些东西。这可能不是一个精确的解决方案,您可能需要稍微研究一下
    【解决方案3】:

    useState 本质上是异步的,但不返回承诺,但要解决 useState 的异步性质和快速的脏修复将只是在您的数据上放置一个空传播,例如

    幻灯片?.map

    但我将如何做到这一点是这样的: 只是给你一些想法

    import SLIDES from ....slides.etc
    
    const [slideIndex, setSlideIndex]=useState(0)
    
    <item onClick={()=>{setSlideIndex(slideIndex + 1)}} >
    {SLIDES[slideIndex]}
    </item>
    

    只是给你一个想法的例子

    【讨论】:

      猜你喜欢
      • 2020-03-23
      • 2021-05-17
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 1970-01-01
      • 2020-06-22
      • 2015-04-21
      • 2019-06-06
      相关资源
      最近更新 更多