React: React Hook useEffect memiliki ketergantungan yang hilang: 'xxx' ?

Dibuat pada 12 Jun 2019  ·  69Komentar  ·  Sumber: facebook/react

Hai, saya sedang meneliti React Hook baru-baru ini, itu bagus.

Tapi saya punya masalah, saya tidak menemukan jawaban yang cocok di dokumentasi React Hook dan google untuk menyelesaikan masalah saya.

Ketika saya menggunakan fungsi di useEffect dan komponen fungsi bersama-sama, saya menemukan peringatan bahwa saya tidak menentukan ketergantungan di useEffect, seperti yang ditunjukkan di bawah ini:

image

Apakah ada cara untuk menyelesaikan masalah saya? Saya telah memikirkannya sejak lama.

Apa perilaku saat ini?

React Hook useEffect has a missing dependency: 'setCenterPosition'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)

Repro mini dalam kode dan kotak:
https://codesandbox.io/s/trusting-kowalevski-oet4b

Solusi apa pun, terima kasih.

Kode

function App() {
  const [elePositionArr, setElePositionArr] = useState([
    { left: 0, top: 0 },
    { left: 0, top: 0 },
    { left: 0, top: 0 }
  ]);
  const stageRef = useRef(null);
  const Stage = useRef({ w: 0, h: 0 });
  const currentIndex = useRef(0);

  useEffect(() => {
    // Record the size of the stage
    const stageW = stageRef.current.scrollWidth;
    const stageH = stageRef.current.scrollHeight;

    Stage.current = { w: stageW, h: stageH };

    const index = Math.floor(Math.random() * 3);
    currentIndex.current = index;
    setCenterPosition(index);
  }, []);

  // Centering a block element
  function setCenterPosition(index) {
    let cacheEle = elePositionArr;
    // calc center postion
    const centerOfLeft = Stage.current.w / 2 - 25;
    const centerOfTop = Stage.current.h / 2 - 25;

    cacheEle = cacheEle.map((item, i) => {
      const randomWNum = Math.floor(Math.random() * Stage.current.w) - 50;
      const randomHNum = Math.floor(Math.random() * Stage.current.h) - 50;
      const randomLeft = randomWNum <= 50 ? 50 : randomWNum;
      const randomTop = randomHNum <= 50 ? 50 : randomHNum;
      let newItem;

      if (index === i) {
        newItem = { left: centerOfLeft, top: centerOfTop };
      } else {
        newItem = { left: randomLeft, top: randomTop };
      }

      return newItem;
    });

    setElePositionArr(cacheEle);
  }

  function handleClickLi(index) {
    if (currentIndex.current !== index) {
      setCenterPosition(index);
      currentIndex.current = index;
    }
  }

  return (
    <div className="container">
      <div className="stage" ref={stageRef}>
        {elePositionArr.map((item, index) => (
          <div className="ele" key={index} style={item}>
            {index}
          </div>
        ))}
      </div>
      <ul className="nav">
        {elePositionArr.map((item, index) => (
          <li
            className={currentIndex.current === index ? "active-li" : ""}
            onClick={() => {
              handleClickLi(index);
            }}
            key={"li" + index}
          >
            {index}
          </li>
        ))}
      </ul>
    </div>
  );
}

Komentar yang paling membantu

Ketika ribuan pengembang menghadapi masalah yang sama dan tim pengembang Bereaksi menutup utas dan mengabaikan semua orang:
8d6

Semua 69 komentar

Ini harus menjawab pertanyaan Anda:

https://reactjs.org/docs/hooks-faq.html#is -it-safe-to-omit-functions-from-the-list-of-dependencies

Ini harus menjawab pertanyaan Anda:

https://reactjs.org/docs/hooks-faq.html#is -it-safe-to-omit-functions-from-the-list-of-dependencies

@gaearon
Tidak menyelesaikan masalah saya, masalah saya lebih khusus, menjalankan functionsetElePositionArr saya ingin mengaktifkan componentDidMount dan handleClick, tetapi fungsi React Hook tidak memenuhi persyaratan saya dan peringatan muncul.

Pertanyaan saya adalah: React Hook tidak dapat memanggil fungsi dalam useEffect dan komponen fungsi ke operasi setState?

Biarkan terbuka sehingga kami dapat menanggapi pertanyaan kedua.

Saya mengalami peringatan ESLint yang sama tetapi dalam kasus saya, saya ingin melakukan panggilan async ketika komponen saya dipasang.

const ManageTagsModalBody: React.FC<IProps> = ({ children, getTags }) => {
  useEffect(() => {
    getTags();
  }, []);

  return <div>{children}</div>;
};
Line 12:  React Hook useEffect has a missing dependency: 'getTags'. Either include it or remove the dependency array. If 'getTags' changes too often, find the parent component that defines it and wrap that definition in useCallback  react-hooks/exhaustive-deps 

ManageTagsModalBody tidak bergantung pada data apa pun, ia hanya digunakan sebagai pembungkus untuk memuat data kapan pun komponen dirender. Perlu diperhatikan bahwa komponen children menggunakan data yang telah diambil oleh getTags .

Saya tidak yakin apa yang harus ditambahkan ke daftar dependensi.

saya tertarik untuk penjelasan juga.
React Hook useEffect memiliki ketergantungan yang hilang: 'dispatch'.

  useEffect(() => {
    axios.get('http://localhost:8000/api/future-registrations')
      .then((result) => {
        dispatch(initRegistrationsAction(result.data));
      });
  }, []);

Masalah yang sama di sini. Aturan yang aneh.

Sama disini. Sesederhana di https://github.com/facebook/react/issues/15865#issuecomment -506503377:

  useEffect(() => {
    dispatch(fetchPosts());
  }, []);

Apakah ada cara untuk menekan peringatan ini?

Seperti yang disarankan dalam pesan peringatan, Anda dapat melakukan seperti itu

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

@fayway maka setiap kali initFetch dan nilai pengiriman berubah, panggilan balik useEffect akan dieksekusi.
dia ingin melakukan panggilan balik sekali

@shkyung Dalam kasus saya, initFetch tidak akan mengubah sebab pengiriman (store.) juga tidak

Mungkin bisa seperti ini

const setCenterPosition = useRef(null)
setCenterPosition.current = useCallback( ()=>{} ,[deps])

effect(()=>{ setCenterPosition.current() },[setCenterPosition,otherDeps])

Perubahan ini tampaknya agak konyol dan kontra produktif. Alih-alih kembalikan ke versi sebelumnya dan biarkan Anda memikirkan yang ini.

Punya masalah yang sama. Saya hanya ingin pengambilan saya diaktifkan di componentDidMount. Menambahkan ketergantungan ke hasil larik berulang kali mencapai titik akhir.

React Hook useEffect memiliki ketergantungan yang hilang: 'dispatch'.

const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;

useEffect(() => {
  const id = setInterval(() => {
    dispatch({ type: 'tick' }); // Instead of setCount(c => c + step);
  }, 1000);
  return () => clearInterval(id);
}, [dispatch]);

Ini tampaknya merupakan kasus penggunaan yang cukup umum - yang pernah saya alami pada proyek saya saat ini.

Anda ingin menjalankan kait efek hanya satu kali, tetapi ADA ketergantungan, meskipun Anda hanya peduli dengan statusnya saat startup. Saat ini menggunakan
// eslint-disable-next-line react-hooks/exhaustive-deps ,
untuk mematikan aturan linting tetapi akan menyenangkan untuk tidak harus dalam kasus ini.

Ini tampaknya merupakan kasus penggunaan yang cukup umum - yang pernah saya alami pada proyek saya saat ini.

Anda ingin menjalankan kait efek hanya satu kali, tetapi ADA ketergantungan, meskipun Anda hanya peduli dengan statusnya saat startup. Saat ini menggunakan
// eslint-disable-next-line react-hooks/exhaustive-deps ,
untuk mematikan aturan linting tetapi akan menyenangkan untuk tidak harus dalam kasus ini.

Menutup Lint hanyalah solusi sementara, kunci masalah ini tidak cukup untuk memahami kaitnya.

Masalah yang sama di sini. Saya hanya ingin menjalankan fungsi di dalam useEffect() sekali, memiliki [] sebagai parameter kedua melakukan apa yang saya inginkan, tetapi terus memberikan peringatan ini.

Peringatan yang aneh karena saya belum pernah melihatnya sampai hari ini di proyek baru. Itu merusak kasus penggunaan memiliki sesuatu yang dipanggil hanya sekali ketika komponen telah dipasang. Sepertinya tidak ada solusi apa pun kecuali mengabaikan peringatan serat.

Saya ingin memasukkan dua sen saya di sini. Khususnya dengan menggunakan Axios untuk membatalkan permintaan jaringan. Akan membuat masalah terpisah jika diperlukan tetapi merasa masalah ini secara langsung mempengaruhi diri saya sendiri. Jadi kait useApi saya adalah sebagai berikut -

import axios, { AxiosInstance } from "axios";
import axiosRetry from "axios-retry";
import { FetchEnv } from "../../utilities";
import { useStorage } from "../useStorage";

export const useApi = ({ isAuth = false, retries = 3 } = {}) => {
  const cancelToken = axios.CancelToken.source();
  const { getItem } = useStorage();

  const getBaseUrl = () => {
    return FetchEnv({
      defaultValue: "http://api.example.com",
      key: "API_URI"
    });
  };

  const authorizedClient = (client: AxiosInstance) => {
    const session = getItem("SESSION", "sessionStorage");
    const hasAccessToken = Boolean(session.tokens.accessToken);

    if (isAuth && !hasAccessToken) {
      console.error("No access token found to initiate authorized request.");
      return client;
    } else {
      client.defaults.headers[
        "Authorization"
      ] = `Bearer ${session.tokens.accessToken}`;
      return client;
    }
  };

  const buildFetch = (): AxiosInstance => {
    const client = axios.create({
      baseURL: getBaseUrl(),
      cancelToken: cancelToken.token
    });
    axiosRetry(client, { retries });
    return isAuth ? authorizedClient(client) : client;
  };

  return {
    cancelRequest: cancelToken.cancel,
    fetch: buildFetch()
  };
};

Untuk menggunakan hook ini di dalam sebuah komponen, cukup definisikan seperti di bawah ini maka hook ini dapat digunakan untuk membuat panggilan yang diautentikasi dan tidak diautentikasi baik saat dipasang, dalam useEffect, sebagai bagian dari event handler, dll. cancelRequest adalah token pembatalan unik yang dihasilkan yang dipasangkan dengan instans aksio "ambil" relatif terhadap komponen ini.

const { cancelRequest, fetch } = useApi();

Jika karena alasan apa pun komponen ini turun, berikut ini disebut:

  useEffect(() => {
    return () => {
      cancelRequest("Auth network request cancelled");
    };
  }, []);

Sekarang bekerja dengan sempurna saat ini. Namun, peringatan, ketika diterapkan (menempatkan cancelRequest sebagai dependensi useEffect) segera MEMBATALKAN permintaan jaringan saat metode pengambilan dipanggil. Saran apa pun akan sangat dihargai namun tampaknya satu-satunya solusi saat ini adalah menonaktifkan ts-lint ini untuk terus maju ...

Saya pikir masalahnya di sini mungkin cara kita berpikir tentang kait. @luojinghui 's komentar menunjukkan bahwa ada lebih banyak untuk ini daripada memenuhi mata. Mungkin kita perlu berpikir berbeda? Saya telah dapat menghapus masalah ini di salah satu kait saya dengan beberapa refactoring. Kode lebih jelas sebagai hasilnya.

Ini membuat saya heran jika, di @ Stoner609 's contoh di atas ini, kode waktu harus di hook useCallback? Masih aneh memiliki fungsi (yang seharusnya statis) sebagai ketergantungan.

Saya pikir kasus ini harus menjadi semacam pengecualian

Jika Anda ingin menjalankan fungsi hanya sekali saat komponen dimuat dan yang mengambil parameter, maka Anda dapat menggunakan useRef untuk menghindari peringatan. Sesuatu seperti ini berfungsi:

  const InitialPropA= useRef(propA);
  useEffect(() => {
    myFunction(InitialPropA.current);
  }, [myFunction, InitialPropA]);

Seperti yang disarankan dalam pesan peringatan, Anda dapat melakukan seperti itu

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

Sebanyak saya menyukai balasan cerdas ini, biasanya inilah yang terjadi dalam kode saya.
Saya tidak ingin semua peringatan sial tentang pengiriman hilang.

Saya ingin tahu persis apa dan mengapa terjadi dalam rangkaian misteri itu :)

Seperti yang disarankan dalam pesan peringatan, Anda dapat melakukan seperti itu

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

ini juga dapat membuat kebocoran memori jika terjadi sesuatu seperti API, itu akan membuat panggilan pada loop tak terbatas.

Benar-benar membutuhkan perbaikan untuk ini. Itu terus memberi saya kesalahan dan tidak ada ide bagaimana menyelesaikannya jika Anda ingin menjalankan fungsi di dalam useEffect() sekali saja.

Menghadapi kesalahan yang sama -

React Hook useEffect memiliki ketergantungan yang hilang: 'props'. Namun, 'alat peraga' akan berubah ketika perubahan prop, sehingga memperbaiki disukai adalah untuk destructure luar objek 'props' dari panggilan useEffect dan merujuk kepada mereka alat peraga tertentu di dalam useEffect / lengkap-deps kait bereaksi-

Kode -

  useEffect(() => {
    props.dispatch(searchMediaAction("rain"));
  }, []);

@luojinghui : Beri tahu saya jika Anda menyelesaikan kesalahan serat

kesalahan yang sama

permasalahan yang sama. Saya ingin meniru perilaku componentDidMount; Saya tidak tertarik dengan peringatan itu; Saya tidak ingin menjalankan kembali hook ketika ada perubahan

Saya akan mengusulkan untuk tidak menampilkan peringatan ini ketika argumen kedua untuk useEffect() adalah [] , b/c dalam hal ini pengembang tahu bahwa efek ini hanya akan berjalan sekali dan oleh karena itu _ingin_ menggunakan nilai prop awal dan tidak peduli jika prop berubah pada render berikutnya.

Kasus 1:
Jika kita ingin fungsi berjalan pada inisialisasi serta ketika parameter yang ditentukan berubah nilainya (seperti yang disarankan oleh peringatan lint), maka kita meneruskan parameter tersebut ke dalam array.

Kasus 2:
Jika kita ingin fungsi berjalan tepat satu kali pada initialization , maka kita menggunakan array kosong sehingga efeknya hanya dipicu satu kali.

Dalam Kasus 2, kita pada dasarnya mendengarkan event componentDidMount sesuai dengan spesifikasi dokumentasi React Hook. Kesalahan lint tidak konsisten dengan dokumentasi React Hook dan harapan pengembang.

Mengapa ini ditutup?

Ada solusi?

@kennylbj

Setelah mencoba banyak saran berbeda, inilah yang akhirnya berhasil bagi saya. Saya lebih suka tidak menggunakan eslint-disable, ketika mencoba menjaga kode relatif sederhana untuk pemula. Pendekatan ini memungkinkan Anda untuk meneruskan fungsi pengiriman Anda tanpa menjalankannya di dalam useCallback. Semoga ini membantu.

```javascript
// ... di dalam komponen fungsi
const { dispatchFunc } = customHook();
const memoizeDispatchFunc = useCallback(dispatchFunc, []);

useEffect(() => {
memoizeDispatchFunc();
}, [memoizeDispatchFunc]);
````

Bisakah kita menghapus array kosong? Melakukannya tampaknya berhasil (kode masih berjalan seperti yang diharapkan, dan peringatan hilang), tetapi saya tidak tahu apakah ada alasan mengapa kita tidak melakukannya seperti itu.

useEffect(()=>{ myFunc(); } )

@robthedev Solusi hebat.
Kami bahkan dapat menyederhanakan kode Jika kami menggunakan redux:

const dispatch = useDispatch();

// redux can guarantee that the dispatch function will not change between renders.
// so we don't need to wrap it with useCallback for now.
useEffect(() => {
  dispatch(actions());
}, [dispatch]);

Dan artikel ini sangat membantu saya.

Solusi untuk masalah ini bukanlah menghilangkan ketergantungan, sebaliknya, kita dapat mengangkat fungsi yang tidak memerlukan props atau status di luar komponen atau, membungkusnya ke dalam useCallback di mana mereka didefinisikan.

@kennylbj

Setelah mencoba banyak saran berbeda, inilah yang akhirnya berhasil bagi saya. Saya lebih suka tidak menggunakan eslint-disable, ketika mencoba menjaga kode relatif sederhana untuk pemula. Pendekatan ini memungkinkan Anda untuk meneruskan fungsi pengiriman Anda tanpa menjalankannya di dalam useCallback. Semoga ini membantu.

// ... inside function component
const { dispatchFunc } = customHook();
const memoizeDispatchFunc = useCallback(dispatchFunc, []);

useEffect(() => {
  memoizeDispatchFunc();
}, [memoizeDispatchFunc]);

Dengan saya contoh di atas tidak berfungsi.

Dapatkan kesalahan ini:
TypeError: Cannot destructure property 'dispatchFunc' of 'componentDidMount(...)' as it is undefined.

@react-team: Selamat Kode Boilerplate. :) Bisa tolong dilogikakan dan dibaca lagi... event seharusnya mudah digunakan... tanpa harus menulis 5+ baris logika hanya untuk memanggil sebuah fungsi.

Bagi saya, kesalahan muncul dalam situasi berikut:

  useEffect(() => {
    props.getTasks()
  }, [])

Saya mengoreksinya seperti ini:

const { getTasks } = props
  useEffect(() => {
    getTasks()
  }, [getTasks])

Ketika ribuan pengembang menghadapi masalah yang sama dan tim pengembang Bereaksi menutup utas dan mengabaikan semua orang:
8d6

masalah saya berbeda dari yang lain di utas ini, jadi saya akan membagikannya jika ada jiwa malang lainnya yang jatuh ke lubang kelinci saya baru saja turun selama 1 1/2 jam

function hydrate( _state, _errors=false) {
    console.log('hydrate()');
    setState({...state,..._state});
    if(_errors){
        setErrors({...errors,..._errors});
    }
}

pengguna diharapkan untuk menggunakan ini dengan useEffect() untuk menghidrasi status mereka seperti:

useEffect(()=>{
    hydrate({
        name:'Garrett',
        email:'[email protected]',
        newsletter: 'yes'
    });
},[hydrate]); //unfortunately, this causes an infinite render, because hydrate will always change

jadi untuk mengatasi ini, saya baru saja mengubah fungsi hidrat saya menjadi dibungkus useCallback() , sekarang tidak bermutasi setiap render ( saya kira ), dan seharusnya ini lebih baik untuk kinerja, yang jika itu ternyata benar saya akan mengimplementasikan ini untuk semua fungsi pembantu saya yang dikembalikan dari kait khusus saya.

const hydrate = useCallback(( _state, _errors=false )=> {
    console.log('hydrate()');
    setState({...state,..._state});
    if(_errors){
        setErrors({...errors,..._errors});
    }
},[]);

adakah yang bisa mengkonfirmasi jika ini benar, useCallback mencegah hydrate bermutasi dalam render, dan dengan demikian mungkin lebih baik untuk membungkus semua fungsi tersebut dalam useCallback untuk kinerja yang lebih baik ?

redux can guarantee that the dispatch function will not change between renders.

Apa kamu yakin akan hal itu?
Tautan ke dokumen di mana dikatakan demikian.

Periksa https://overreacted.io/a-complete-guide-to-useeffect/#decoupling -updates-from-actions untuk detail lebih lanjut atau Anda dapat memeriksa kode sumber useEffect untuk detail implementasi.

Di sini saya hanya merujuk apa yang dikatakan Dan:

Jawabannya adalah React menjamin fungsi pengiriman konstan sepanjang umur komponen. Jadi contoh di atas tidak perlu berlangganan ulang interval.

menjamin fungsi pengiriman menjadi konstan

Keren Terimakasih!

Ketika ribuan pengembang menghadapi masalah yang sama dan tim pengembang Bereaksi menutup utas dan mengabaikan semua orang:
8d6

Cukup banyak ini. Di sini saya mencoba kait dan saya disambut dengan peringatan ini yang tidak masuk akal dan tidak tercakup dalam dokumen resmi mana pun. Benar-benar membuat Anda bertanya-tanya apakah kait siap untuk pekerjaan serius ketika kasus penggunaan dasar seperti "jalankan efek ini hanya sekali" memberikan banyak masalah.

Yah, tidak banyak lagi yang bisa dikatakan, selain fakta bahwa utasnya ditutup smh.

Menghadapi masalah yang sama!

LARUTAN,
(yang berhasil untuk saya):

const onInit = function(){ 
    console.log('initiated', Date.now());
}

useEffect(onInit, []);

Saya lebih suka masalah diperbaiki di sisi linting, tapi hei ...

@ ra30r solusi yang bagus tetapi bertanya-tanya apakah itu dapat membuat efek samping? :pemikiran:

Tetap tidak ada? 😔

Saya memiliki kasus di mana saya belajar untuk memicu kesalahan validasi formulir dari kursus di Udemy.

Ini memicu "pengiriman" ketergantungan yang hilang, tetapi masih berfungsi:

  useEffect(() => {
    if (state.business_name.value) {
      const delay = setTimeout(() => dispatch({ type: "businessNameAfterDelay" }), 1000)
      return () => clearTimeout(delay)
    }
  }, [state.business_name.value])

Menggunakan contoh @ ra30r , saya mengubahnya menjadi ini untuk menghapus kesalahan:

  const businessNameAfterDelay = function () {
    if (state.business_name.value) {
      const delay = setTimeout(() => dispatch({ type: "businessNameAfterDelay" }), 1000)
      return () => clearTimeout(delay)
    }
  }

  useEffect(businessNameAfterDelay, [state.business_name.value])

Mengapa ini ditutup?

Saya percaya jawaban telah diberikan di suatu tempat.. lol.. anyway.. solusinya adalah melakukan seperti ini:
useEffect(() => { dispatch(); }, [dispatch]);

semoga ini membantu!!

Mengapa ini ditutup?

Saya percaya jawaban telah diberikan di suatu tempat.. lol.. anyway.. solusinya adalah melakukan seperti ini:
useEffect(() => { dispatch(); }, [dispatch]);

semoga ini membantu!!

Ya, solusi itu berhasil, kata @kennylbj di sini beberapa waktu lalu.
Mengapa masalah ini ditutup? Ada meme di sini juga tentang itu ... xd

Masalah saya agak seperti ini (kode contoh):

  const [userStatus, setUserStatus]: any = React.useState([]);
  const [userData, setUserData]: any = React.useState([]);

  useEffect(() => {
    setUserStatus(!userStatus);
    return () => {};
  }, [userData]);

Jadi seperti pada kode yang ingin Anda ubah nilai userStatus ketika ada perubahan pada userData dan dalam hal ini jika Anda ingin memeriksa nilai userStatus Anda telah menambahkannya ke deps:

  const [userStatus, setUserStatus]: any = React.useState([]);
  const [userData, setUserData]: any = React.useState([]);

  useEffect(() => {
    setUserStatus(!userStatus);
    return () => {};
  }, [userData, userStatus]);

dalam skenario ini itu akan menjadi loop yang tidak pernah berakhir

@spmsupun
Anda dapat menggunakan gaya callback useState untuk menghindari pengenalan variabel userStatus dalam larik dependensi useEffect.

 useEffect(() => {
    setUserStatus(prevState => !prevState);
    return () => {};
  }, [userData]);

Dan ini disebut pembaruan fungsional .

Solusi -> tambahkan saja pengiriman terakhir untuk ketergantungan
React Hook useEffect memiliki ketergantungan yang hilang: 'dispatch'.

  useEffect(() => {
    axios.get('http://localhost:8000/api/future-registrations')
      .then((result) => {
        dispatch(initRegistrationsAction(result.data));
      });
**  }, [dispatch]);**

@kennylbj Ini bagus ketika Anda berurusan dengan satu keadaan, skenario saya yang sebenarnya adalah dengan alat peraga. Saya mengirim alat peraga dari orang tua dan itu berubah dua kali sehingga efek pengguna memanggil dua kali tetapi saya menjalankan pendengar di dalamnya dan itu akan mendengarkan dua kali.

@spmsupun Tapi saya pikir cukup normal untuk membatalkan pendaftaran pendengar sebelumnya dan mendaftarkan pendengar baru setiap kali variabel dalam array dependensi berubah (mis. Ketika userId di alat peraga berubah, pendengar juga perlu diubah). Dan perilaku inilah yang diharapkan dimiliki oleh reaksi.

Jika Anda masih tidak ingin membuat pendengar dipanggil dua kali, saya pikir Anda harus lebih berhati-hati dengan alat peraga yang diteruskan ke sana dan memastikan itu tidak akan diubah selama render.

@kennylbj baik saya membatalkan pendaftaran tetapi tetap saja itu bukan praktik yang baik
image
Kira saya harus menangani ini dari kelas pendengar,

Sepertinya pendengar Anda dipanggil dua kali meskipun id soketnya sama.

Saya tidak berpikir ini akan terjadi jika situasi berikut memenuhi:

ts // call useEffect if and only if sockeId changed. useEffect(() => { const unregister = register(socketId); return () => unregister(socketId); }, [socketId])

Apakah ada variabel lain dalam array dependensi yang berubah selama render yang berbeda dan menyebabkan perilaku ini?

Ya 3 dependensi, tapi saya mencari tahu dengan cara yang berbeda

Pien

Seperti yang disarankan dalam pesan peringatan, Anda dapat melakukan seperti itu

const initFetch = useCallback(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  useEffect(() => {
    initFetch();
  }, [initFetch]);

wow,非常感谢你🙏

Cuplikan kode di bawah ini berfungsi sangat baik untuk saya

Pada Komponen melakukan mount

const onInit = () => getUsers()
useEffect(onInit, [])

Pada perubahan parameter

const onInit = () => getUser(id)
useEffect(onInit, [id])

Solusi terbaik: react-hooks/exhaustive-deps: "off"
Saya tidak pernah menemukan fitur eslint ini berguna. Pernah.

Cuplikan kode di bawah ini berfungsi sangat baik untuk saya

Pada Komponen melakukan mount

const onInit = () => getUsers()
useEffect(onInit, [])

Pada perubahan parameter

const onInit = () => getUser(id)
useEffect(onInit, [id])

kerja bagus.

Saya tidak berpikir dokumen reaksi cukup mencakup kasus penggunaan @luojinghui , itu juga sama dengan yang saya miliki:

Kami memiliki beberapa cara untuk memanggil fungsi yang diberikan, yaitu: setCenterPosition() . Itu bisa dipanggil dengan memperhatikan perubahan status (dihubungkan melalui useEffect ), penangan klik (dipanggil langsung), dll.

Dokumen reaksi menyarankan

Inilah sebabnya mengapa biasanya Anda ingin mendeklarasikan fungsi yang dibutuhkan oleh efek di dalamnya

Tetapi biasanya dalam contoh dunia nyata, kita perlu menggunakan kembali fungsi seperti biasanya dengan metode instance pada komponen kelas ( this.setCenterPosition(...) ), dan saya mulai bertanya-tanya apakah kait sebenarnya bagus untuk fitur-penuh, komponen yang kompleks.

Saya sebenarnya tidak yakin, tapi mungkin solusinya adalah useCallback

const setCenterPosition = useCallback(() => {
  ...
}, [Stage, elePositionArr, setElePositionArr]);

useEffect() => {
  ...
}, [stageRef, Stage, currentIndex, setCenterPosition]);

...tapi itu agak menjijikkan bagi saya, dan saya berharap ada cara yang lebih bersih. Mungkin @gaearon bisa mengkonfirmasi?

menghadapi masalah yang sama saya dapat menonaktifkan peringatan bu menggunakan baris ini di akhir useEffect // eslint-disable-next-line react-hooks/exhaustive-deps tetapi saya tidak ingin menggunakannya

Ini kode saya

`const [item, setItems] = useState([
{
nama: "tes 1",
nomor: 1
},
{
nama: "tes 2",
nomor: 2
},
{
nama: "tes 3",
nomor: 3
},
{
nama: "tes 4",
nomor: 4
},
{
nama: "tes 5",
nomor: 5
}
]);

useEffect(() => {
const intervalId = setInterval(() => {
setItems(shuffleArray(item));
}, 1000);
kembali () => {
clearInterval(intervalId);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Solusi saya untuk masalah ini adalah berhenti menggunakan React Hooks untuk kasus ini. Jika komponen Anda sangat membutuhkan logika keadaan dan peristiwa siklus hidup seperti componentDidMount , gunakan saja komponen kelas dan selamatkan diri Anda dari sakit kepala. Komponen kelas baik-baik saja, dan jika utas ini membuktikan sesuatu, React Hooks tidak siap untuk sepenuhnya menggantikannya ketika logika keadaan kompleks atau peristiwa siklus hidup diperlukan (juga tidak memberikan keuntungan apa pun dalam sebagian besar kasus ini - apakah kode Anda _benar-benar_ itu jauh lebih baik karena telah menggunakan React Hooks?).

Saya akan membatasi penggunaan React Hooks saya sendiri untuk yang sederhana seperti useState untuk mengatur flag boolean dan hal semacam itu. Jika suatu komponen menjadi cukup kompleks untuk membutuhkan useEffect Saya menganggapnya sebagai tanda bahwa mungkin komponen kelas lebih cocok.

(Diedit untuk kejelasan).

Ini solusi saya untuk saat ini:

const mounted = () => {
  dispatch(something());
}

useEffect(mounted, []);

Terima kasih @ra30r react/issues/15865#issuecomment-651254164

Apakah halaman ini membantu?
0 / 5 - 0 peringkat