useEffect 中的 setState 不适用于 React JS 中的 First Render

setState inside useEffect not working on First Render in React JS

我正在构建一个使用 React Awesome Slider 的 ReactJS 组件。 我要创建的是一个滑块,下面有一个描述 div,它会更改文本,然后我更改幻灯片。

现在,我找到了让它工作的方法,但我对对象的 setState 有疑问,这是代码。

滑块:

const AutoplaySlider = withAutoplay(AwesomeSlider);

const StaticSlider = ({slider}) => {
    var images = "";
    var length=0;
   
    const [current, setCurrent] = useState(0);
    const [title, setTitle] = useState([]);
    const [description, setDescription] = useState([]);
   
    switch (slider) {

        case 'portfolio_sviluppo_software':

            images = portfolio_description.sviluppo_software;
            length= portfolio_description.sviluppo_software.length;
          
            break;
        case 'portfolio_domotica':

            images = portfolio_description.domotica;
            length= portfolio_description.domotica.length;
            
            break;
        case 'portfolio_digital_signage':

            images = portfolio_description.digital_signage;
            length= portfolio_description.digital_signage.length;
           
            break;
        case 'portfolio_ricerca_e_sviluppo':

            images = portfolio_description.ricerca_e_sviluppo;
            length= portfolio_description.ricerca_e_sviluppo.length;
           
            break;
    }
   
    useEffect(
        () => {
            setTitle(
                images.map(
                    (slide) => (slide.title)
                )
            );
            setDescription(
                images.map(
                    (desc) => (desc.data)
                )
            );
            }, [images]
            
    );
   
    return(
        <div>
            <AutoplaySlider
                play={true}
                cancelOnInteraction={true}
                interval={0}
                onTransitionStart={slide => setCurrent(slide.nextIndex)}
                className="sliderHome"
                >
                {images.map((image, index) => {
                        
                    let src = "/image/slider/portfolio/"+image.image;
                    //console.log(src);
                    return (
                        <div key={index} data-src={src}>
                        </div>
                    );
                
                })}
            </AutoplaySlider>
            <GalleryCaption selected={current} title={title} description={description} area={slider}/>
        </div>
)
};

export default StaticSlider;

描述生成器


const GalleryCaption = ({ selected = 0, title = [], description= [], area = 0 }) => {
  const formattedIndex = selected + 1;
  var title = title[selected];
  var data = description[selected];
  return (
    <div className="containerDivDescriptionPortflio">
      <div className="DivDescriptionPortflio">
          <p id ={"description_portfolio_"+area} className="paragDescriptionPortflio" >
            <h4>{title}</h4>
            <hr></hr>
            {
                data.map((val) => (
                 <div className="rowDescriptionPortfolio">
                   <div className="divIndexPortfolio" dangerouslySetInnerHTML={{ __html: val.index }} >

                   </div>
                   <div className="divTextPortfolio" dangerouslySetInnerHTML={{ __html: val.text }} >
                     
                   </div>
                 </div>
            ))}
          </p>
      </div>
  </div>

  );
};

export default GalleryCaption;

对象示例

{
            "title":"text",
            "data":[
                {
                    "index":"text",
                    "text": "text"
                },
                {
                    "index":"text",
                    "text": "text"
                }
            ],
            "image": "folder/image.jpg"
        },

(这​​是该类对象数组的一个元素) 现在的主要问题是,如果在使用效果中,我只调用 setTitle 函数,一切都会正常工作,但如果我也使用 setDescription,一切都会停止工作。我没有收到特定错误,但出现白屏。

我得到的错误

Warning: Each child in a list should have a unique "key" prop.

Check the render method of `PortfolioArea`. See https://reactjs.org/link/warning-keys for more information.
    at div
    at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
    at http://localhost:3000/static/js/bundle.js:4509:78
    at Routes (http://localhost:3000/static/js/bundle.js:177110:5)
    at Router (http://localhost:3000/static/js/bundle.js:177043:15)
    at BrowserRouter (http://localhost:3000/static/js/bundle.js:176523:5)
    at App
    at AppProvider (http://localhost:3000/static/js/bundle.js:3289:5)

Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.

* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state

Please update the following components: AwesomeSlider
The above error occurred in the <GalleryCaption> component:
    
        at GalleryCaption (http://localhost:3000/static/js/bundle.js:973:5)
        at div
        at StaticSlider (http://localhost:3000/static/js/bundle.js:3049:5)
        at div
        at PortfolioArea (http://localhost:3000/static/js/bundle.js:1618:5)
        at http://localhost:3000/static/js/bundle.js:4510:78
        at Routes (http://localhost:3000/static/js/bundle.js:177111:5)
        at Router (http://localhost:3000/static/js/bundle.js:177044:15)
        at BrowserRouter (http://localhost:3000/static/js/bundle.js:176524:5)
        at App
        at AppProvider (http://localhost:3000/static/js/bundle.js:3290:5)

考虑向树中添加错误边界以自​​定义错误处理行为。 访问 https://reactjs.org/link/error-boundaries 以了解有关错误边界的更多信息。`

我尝试将 useEffect 的第二个参数更改为 null 并且还为每个参数使用唯一状态,但问题似乎是每次我尝试使用 useEffect 中的对象设置状态时,在第一次渲染时,我总是在该状态中得到一个空值。

有什么建议吗?

我认为在StaticSlider中,由于imageslength是根据sliderprop计算的,我建议使用useMemo()来计算它们slider 更改,而不是将值重新分配给 var 变量,这在 React 中不应该这样做,并且会引发错误。

const StaticSlider = ({slider}) => {
    const images = useMemo(
      () => {
        // calculate and return images value
        // with `switch`
        switch (slider) {
          // ...
          default:
            return [];
        }
      },
      [slider]
    );

    const length = useMemo(
      () => {
        // calculate and return length value
        // with `switch`
        switch (slider) {
          // ...
          default:
            return 0;
        }
      },
      [slider]
    );

请注意,您当前的 switch 块没有 default 案例,您应该考虑返回一个带有 imageslength 初始值的默认案例。

另请注意,images 的初始赋值是 images = "",这将使它成为 string,但在 setDescription() 中,您调用的是 images.map()是一个数组方法,所以当 images 是一个空字符串时,它不会在组件的 初始渲染 上工作。我认为这就是导致错误的原因。

images = [] or default: return [] for images inside switch statement 应该更好。

最后,我认为您可以考虑在 useEffect() 中使用条件检查,仅在 titledescription 上使用 setState,当 images 已经填充时(有长度)。

    useEffect(
        () => {
          if (images.length) {
            setTitle(
                images.map(
                    (slide) => (slide.title)
                )
            );

            setDescription(
                images.map(
                    (desc) => (desc.data)
                )
            );
          }
        },
        [images]   
    );