Cara memanggil fungsi memuat dengan Bereaksi useEffect hanya sekali

205

The useEffect Bereaksi kait akan menjalankan disahkan pada fungsi pada setiap perubahan. Ini dapat dioptimalkan agar panggilan hanya ketika properti yang diinginkan berubah.

Bagaimana jika saya ingin memanggil fungsi inisialisasi dari componentDidMountdan tidak menyebutnya lagi pada perubahan? Katakanlah saya ingin memuat entitas, tetapi fungsi pemuatan tidak memerlukan data dari komponen. Bagaimana kita bisa menggunakan useEffectkait ini?

class MyComponent extends React.PureComponent {
    componentDidMount() {
        loadDataOnlyOnce();
    }
    render() { ... }
}

Dengan kait ini bisa terlihat seperti ini:

function MyComponent() {
    useEffect(() => {
        loadDataOnlyOnce(); // this will fire on every change :(
    }, [...???]);
    return (...);
}
Dávid Molnár
sumber

Jawaban:

389

Jika Anda hanya ingin menjalankan fungsi yang diberikan useEffectsetelah render awal, Anda bisa memberikan array kosong sebagai argumen kedua.

function MyComponent() {
  useEffect(() => {
    loadDataOnlyOnce();
  }, []);

  return <div> {/* ... */} </div>;
}
Tholle
sumber
27
Atau jika ada params yang Anda gunakan untuk mengambil data (misalnya id pengguna), Anda bisa melewatkan id pengguna dalam array itu dan jika itu berubah komponen akan mengambil kembali data. Banyak kasus penggunaan akan berfungsi seperti itu.
trixn
4
ya ... lebih lanjut tentang melompat didokumentasikan di sini: reactjs.org/docs/…
Melounek
Ini sepertinya jawaban yang paling sederhana, tetapi ESLint mengeluh ... lihat jawaban lain di utas ini stackoverflow.com/a/56767883/1550587
Simon Hutchison
Cukup masukkan loadDataOnlyOnce ke dalam array dependensi. Apakah itu bekerja?
jpmarks
85

TL; DR

useEffect(yourCallback, []) - akan memicu panggilan balik hanya setelah render pertama.

Penjelasan detail

useEffectberjalan secara default setelah setiap render komponen (sehingga menyebabkan efek).

Saat menempatkan useEffectdi komponen Anda, Anda memberi tahu Bereaksi bahwa Anda ingin menjalankan panggilan balik sebagai efek. Bereaksi akan menjalankan efek setelah rendering dan setelah melakukan pembaruan DOM.

Jika Anda hanya melewati callback - callback akan berjalan setelah setiap render.

Jika melewati argumen kedua (array), Bereaksi akan menjalankan panggilan balik setelah render pertama dan setiap kali salah satu elemen dalam array diubah. misalnya saat menempatkan useEffect(() => console.log('hello'), [someVar, someOtherVar])- panggilan balik akan berjalan setelah render pertama dan setelah render apa pun yang salah satu someVaratau someOtherVardiubah.

Dengan melewatkan argumen kedua array kosong, Bereaksi akan membandingkan setelah setiap render array dan akan melihat tidak ada yang berubah, sehingga memanggil panggil balik hanya setelah render pertama.

Edan Chetrit
sumber
68

gunakan kaitountEffect

Menjalankan fungsi hanya sekali setelah komponen mount adalah pola umum yang membenarkan pengait itu sendiri yang menyembunyikan detail implementasi.

const useMountEffect = (fun) => useEffect(fun, [])

Gunakan dalam komponen fungsional apa pun.

function MyComponent() {
    useMountEffect(function) // function will run only once after it has mounted. 
    return <div>...</div>;
}

Tentang hook useMountEffect

Saat menggunakan useEffectdengan argumen array kedua, Bereaksi akan menjalankan panggilan balik setelah pemasangan (render awal) dan setelah nilai dalam array berubah. Karena kami melewatkan array kosong, itu akan berjalan hanya setelah pemasangan.

Ben Carp
sumber
19
Saya sangat suka jawaban Anda, karena aturan ESLint "react-hooks / exhaustive-deps" akan selalu gagal pada daftar ketergantungan yang kosong. Dan misalnya templat buat-reaksi-aplikasi yang terkenal akan menegakkan aturan itu.
Dynalon
1
Sepenuhnya setuju dengan @Dinalon. Ini harus menjadi solusi yang diterima karena tidak mengganggu aturan
ESLint
Terima kasih @Dinalon dan Mikado68 :-). Keputusan adalah hak istimewa OP. Saya diberitahu tentang komentar Anda, tetapi OP tidak. Anda dapat menyarankannya dengan mengomentari langsung pertanyaan itu.
Ben Carp
2
Sekarang Anda dapat menggunakan useMountketika fungsi efek Anda memerlukan sesuatu dari alat peraga tetapi tidak perlu dijalankan lagi meskipun nilai itu berubah tanpa linter warnig: useEffect(()=>console.log(props.val),[])akan ada peringatan ketergantungan yang hilang tetapi useMount(()=>console.log(props.val))tidak akan menyebabkan peringatan tetapi "tidak berfungsi". Saya tidak yakin apakah akan ada masalah dengan mode bersamaan.
HMR
1
Saya suka yang ini :) Alasan yang sama seperti keadaan sebelumnya; aturan ESLint tidak akan mengeluh tentang ini, ditambah namanya lebih mudah dipahami daripada array kosong
Frexuz
20

Berikan array kosong sebagai argumen kedua useEffect. Ini secara efektif memberi tahu React, mengutip dokumen :

Ini memberi tahu Bereaksi bahwa efek Anda tidak bergantung pada nilai apa pun dari properti atau status, sehingga efek itu tidak perlu dijalankan kembali.

Berikut cuplikan yang dapat Anda jalankan untuk menunjukkan bahwa ia berfungsi:

function App() {
  const [user, setUser] = React.useState(null);

  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        setUser(data.results[0]);
      });
  }, []); // Pass empty array to only run once on mount.
  
  return <div>
    {user ? user.name.first : 'Loading...'}
  </div>;
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

Yangshun Tay
sumber
4

Saya suka mendefinisikan suatu mountfungsi, itu trik EsLint dengan cara yang sama useMounttidak dan saya merasa lebih jelas.

const mount = () => {
  console.log('mounted')
  // ...

  const unmount = () => {
    console.log('unmounted')
    // ...
  }
  return unmount
}
useEffect(mount, [])
ekoologi
sumber
0

Caranya adalah useEffect menggunakan parameter kedua.

Param kedua adalah array variabel yang akan diperiksa komponen untuk memastikannya berubah sebelum rendering ulang. Anda dapat menempatkan bit alat peraga apa pun dan menyatakan bahwa Anda ingin memeriksa.

Atau, jangan masukkan apa pun:

import React, { useEffect } from 'react';

function App() {
  useEffect(() => {

    // Run! Like go get some data from an API.

  }, []); //Empty array as second argument

  return (
    <div>
      {/* Do something with data. */}
    </div>
  );
}

Itu akan memastikan useEffect hanya berjalan sekali.

Catatan dari dokumen:

Jika Anda menggunakan pengoptimalan ini, pastikan array menyertakan semua nilai dari cakupan komponen (seperti properti dan status) yang berubah seiring waktu dan yang digunakan oleh efek. Jika tidak, kode Anda akan merujuk nilai basi dari perenderan sebelumnya.

Farrukh Malik
sumber
3
Jika Anda benar-benar menyalin / menempel dari Trik CSS, paling tidak yang bisa Anda lakukan adalah kredit sumber Anda. css-tricks.com/run-useeffect-only-once
burtyish