【问题标题】:React Hook useEffect has a missing dependency: 'refreshDisplay'. Either include it or remove the dependency arrayReact Hook useEffect 缺少依赖项:'refreshDisplay'。包括它或删除依赖数组
【发布时间】:2021-10-29 00:36:59
【问题描述】:

我是一个相当新的 React 开发人员,我的代码有问题。当我使用 useEffect(() => {}, []) 时,我收到了多个关于缺少依赖项的警告。我正在接受反应培训(下面的代码是我最终项目的摘录),但课程的质量似乎很差。不幸的是,由于 React 以及在 3 个月内学到的所有知识,我必须创建自己的网站。本次培训期间给出的大多数示例都包含具有空依赖项的 useEffect。这是一种不好的做法吗?

当我在 Chrome 中检查时,我有很多警告说“React Hook useEffect 缺少依赖项:''。要么包含它,要么删除依赖项数组”,但我不知道为什么。你能帮我吗?

这是我的代码:

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

import {getAllShopOpinions} from "../../api/shopOpinions"
import {convertDate} from "../../utils/utils"
import {config} from "../../config/config"
import {deleteOpinion} from "../../api/shopOpinions"

//Imports des composants de l'UI externes
import Header from "../headers/header"
import HeaderPages from "../headers/headerPages"
import Footer from "../footer"
import AdminMenu from "../../components/adminMenu"

//Imports depuis la librairie MaterialUI
import { makeStyles } from "@material-ui/styles"
import { Button } from '@material-ui/core'
import DeleteIcon from '@material-ui/icons/Delete'

const AdminShopOpinions = (props) => {

    const headerTitle ="Administration"
    const headerBreadcrumbs = [{value: "Accueil", link:"/"},{value: "Administration", link:"/admin"},{value: "Avis", link:null}]

    const [displayedShopOpinions, setDisplayedShopOpinions] = useState([])

    //Définition des styles MaterialUI
    const useStyles = makeStyles((theme) => ({
        deleteBtn:{
            color:"#cc0e00"
        }
        }));
        
    const classes = useStyles();

    //Au chargement de la page
    useEffect(() => {
        refreshDisplay()
    }, [])

    const refreshDisplay = () => {
        getAllShopOpinions()
        .then(shopOpinionsDB => {
            setDisplayedShopOpinions([])
            loadDisplayedShopOpinions(shopOpinionsDB)
        })
    }

    const deleteDisplayedOpinion = (id, index) => {
        deleteOpinion(id)
        .then(response => {
            refreshDisplay()
        })
    }

    //Chargement des avis à afficher
    const loadDisplayedShopOpinions = (shopOpinions) => {
        for(let i = 0; i < shopOpinions.length; i++){
            setDisplayedShopOpinions(displayedShopOpinions => [...displayedShopOpinions, 
                <article key={shopOpinions[i].id} className="shop-opinion-item">
                    <section className="shop-opinion-infos">
                        <p>" {shopOpinions[i].comment} "</p>
                        <p>Auteur : <em>{shopOpinions[i].first_name} {shopOpinions[i].last_name}</em></p>
                        <p><em>le {convertDate(shopOpinions[i].creation_timestamp)}</em></p>
                    </section>
                    {shopOpinions[i].pict_url &&
                    <section className="shop-opinion-pict">
                        <img src={config.shop_opinion_pict_url + shopOpinions[i].pict_url} alt={"illustration"+shopOpinions[i].id}/>
                    </section>}
                    <Button className={classes.deleteBtn} onClick={(e) => {deleteDisplayedOpinion(shopOpinions[i].id, i)}}><DeleteIcon /></Button>
                </article>])
        }
    }

    //Fonction d'affichage des avis
    const showDisplayedShopOpinions = () => {
        return(
            <section className="shop-opinions-container">
                {displayedShopOpinions.length > 0 ? displayedShopOpinions : <p>Aucun avis à afficher</p>}
            </section>
        )
    }

    return (
        <section className="root">
                <Header />
                <HeaderPages headerTitle={headerTitle} headerBreadcrumbs={headerBreadcrumbs}/>
                <section className="admin-container">
                    <AdminMenu />
 
                    <section className="admin-content">
                        <h4>Gestion des avis</h4>
                        {showDisplayedShopOpinions()}
                    </section>
                </section>
                <Footer />
        </section>
    )
}

export default AdminShopOpinions```



Thank you in advance and have a nice day :)

【问题讨论】:

标签: reactjs


【解决方案1】:

refreshDisplay() 是分配给变量的函数,如果变量发生变化,效果可能会过时。

忽略 linter 是不好的做法,所以我给你一个更好的办法:

您可以使用Callback() 挂钩来包装函数:

 const refreshDisplay = useCallback(() => {
        getAllShopOpinions()
        .then(shopOpinionsDB => {
            setDisplayedShopOpinions([])
            loadDisplayedShopOpinions(shopOpinionsDB)
        })
    }, [getAllShopOpinions, setDisplayedShopOpinions, loadDisplayedShopOpinions])

它确保函数对所有依赖项保持相同。 这段代码将产生一个无限循环,因为您还需要使用 useCallback 包装其他函数,例如 getAllShopOpinions setDisplayedShopOpinions loadDisplayedShopOpinions

还有其他方法可以做到:

  1. 将函数的声明移到组件之外,那么引用不会改变
  2. 使用 useRef() 确保引用保持不变

然而,最好的做法是使用Callback()

希望这能解释您的问题

【讨论】:

    【解决方案2】:

    忽略 linter 是不是一种不好的做法?是的。你应该总是添加 linter 抱怨的任何缺失的依赖项。一种极端情况是您特别地希望使用空的依赖数组 ([]) 仅在组件挂载上运行效果。

    据我所知,您希望它在组件安装上运行的“特殊”情况。您可以专门为此行禁用 lint 规则。

    useEffect(() => {
      refreshDisplay();
      // Disable for on component mount
      // eslint-disable-next-line react-hooks/exhaustive-deps 
    }, []);
    

    旁注

    您需要将const useStyles = makeStyles(....) 定义移到组件之外,这样useStyles 挂钩就不会在每个渲染周期中重新声明。

    【讨论】:

      猜你喜欢
      • 2020-07-19
      • 2020-05-31
      • 1970-01-01
      • 2021-08-24
      • 2023-04-09
      • 1970-01-01
      • 2021-09-10
      • 2020-09-26
      • 2020-11-05
      相关资源
      最近更新 更多