Anda telah menulis beberapa komponen menggunakan
kait . Mungkin - mereka bahkan membuat aplikasi kecil. Secara umum, Anda cukup senang dengan hasilnya. Anda terbiasa dengan API dan dalam prosesnya menemukan beberapa trik berguna yang tidak jelas. Anda bahkan membuat beberapa
kait Anda sendiri dan mengurangi kode Anda menjadi 300 baris, menempatkan di dalamnya apa yang sebelumnya diwakili oleh pengulangan fragmen program. Apa yang Anda lakukan, Anda menunjukkan kepada rekan kerja. "Bagus sekali," kata mereka tentang proyek Anda.

Tetapi kadang-kadang, ketika Anda menggunakan
useEffect
, komponen-komponen mekanisme perangkat lunak tidak cocok bersama dengan sangat baik. Tampaknya bagi Anda bahwa Anda kehilangan sesuatu. Semua ini mirip dengan bekerja dengan acara siklus hidup komponen berbasis kelas ... tapi benarkah demikian?
Mencoba memahami apa yang sebenarnya tidak cocok untuk Anda, Anda perhatikan bahwa Anda mengajukan pertanyaan berikut:
- Bagaimana cara memainkan
componentDidMount
menggunakan useEffect
? - Bagaimana cara memuat data di dalam
useEffect
? Apa itu []
? - Apakah fungsi perlu ditentukan sebagai dependensi efek?
- Mengapa suatu program kadang-kadang berakhir dalam loop tanpa akhir dari memuat ulang data?
- Mengapa kondisi lama terkadang terlihat di dalam efek atau properti lama ditemukan?
Ketika saya pertama kali mulai menggunakan kait, pertanyaan-pertanyaan ini juga menyiksa saya. Bahkan ketika saya sedang mempersiapkan dokumentasinya, saya tidak dapat mengatakan bahwa saya benar-benar menguasai beberapa seluk-beluknya. Sejak itu, saya memiliki beberapa momen ketika, tiba-tiba, menyadari sesuatu yang penting, saya benar-benar ingin berseru: "Eureka!" Tentang apa yang saya sadari pada saat-saat ini, saya ingin memberi tahu Anda. Apa yang Anda pelajari tentang
useEffect
sekarang akan memungkinkan Anda untuk melihat dengan jelas jawaban yang jelas untuk pertanyaan di atas.
Tetapi untuk melihat jawaban atas pertanyaan-pertanyaan ini, pertama-tama kita harus mengambil langkah mundur. Tujuan artikel ini bukan untuk memberi para pembacanya beberapa petunjuk langkah demi langkah untuk bekerja dengan
useEffect
. Hal ini bertujuan membantu Anda, sehingga
useEffect
"
useEffect
"
useEffect
. Dan terus terang, tidak banyak yang bisa dipelajari. Bahkan, sebagian besar waktu kita akan dihabiskan untuk melupakan apa yang kita ketahui sebelumnya.
Semua yang ada di kepala saya menyatu hanya setelah saya berhenti melihat kaitan
useEffect
melalui prisma metode siklus siklus komponen berbasis komponen.
"Anda harus melupakan apa yang telah diajarkan kepada Anda"
habr.com/ru/company/ruvds/blog/445276/YodaDiasumsikan bahwa pembaca materi ini agak akrab dengan
useEffect API. Ini adalah artikel yang agak panjang, bisa dibandingkan dengan buku kecil. Faktanya adalah saya lebih suka mengekspresikan pikiran saya dengan cara ini. Di bawah ini, sangat singkat, jawaban diberikan untuk pertanyaan-pertanyaan yang dibahas di atas. Mungkin mereka bermanfaat bagi mereka yang tidak punya waktu atau keinginan untuk membaca semua materi.
Jika format di mana kami akan mempertimbangkan
useEffect
, dengan semua penjelasan dan contohnya, sangat tidak cocok untuk Anda, Anda dapat menunggu sedikit - sampai saat ketika penjelasan ini muncul dalam manual lain yang tak terhitung jumlahnya. Ini adalah kisah yang sama dengan perpustakaan Bereaksi itu sendiri, yang pada 2013 adalah sesuatu yang sama sekali baru. Butuh waktu bagi komunitas pengembangan untuk mengenali model mental baru dan untuk materi pendidikan berdasarkan model ini muncul.
Jawaban atas pertanyaan
Berikut adalah jawaban singkat untuk pertanyaan yang diajukan di awal materi ini, ditujukan bagi mereka yang tidak ingin membaca seluruh teks ini. Jika, ketika membaca jawaban-jawaban ini, Anda merasa bahwa Anda tidak benar-benar memahami makna dari apa yang Anda baca, perhatikan materi yang ada. Anda akan menemukan penjelasan terperinci dalam teks. Jika Anda akan membaca semuanya, Anda dapat melewati bagian ini.
▍Cara memainkan componentDidMount menggunakan useEffect?
Meskipun Anda dapat menggunakan
useEffect(fn, [])
untuk memutar fungsionalitas
componentDidMount
, itu tidak sama persis dengan
componentDidMount
. Yaitu, itu, tidak seperti
componentDidMount
, menangkap properti dan status. Karena itu, bahkan di dalam callback, Anda akan melihat properti dan status awal. Jika Anda ingin melihat versi terbaru dari sesuatu, Anda dapat menuliskannya di tautan
ref
. Tetapi biasanya ada cara yang lebih sederhana untuk menyusun kode, jadi melakukan ini adalah opsional. Ingat bahwa model efek mental berbeda dari yang berlaku untuk
componentDidMount
dan metode siklus hidup komponen lainnya. Oleh karena itu, mencoba menemukan padanan yang tepat dapat lebih membahayakan daripada kebaikan. Agar dapat bekerja secara produktif, Anda perlu, untuk berbicara, untuk "berpikir dalam efek." Dasar dari model mental mereka lebih dekat ke implementasi sinkronisasi daripada untuk menanggapi peristiwa dalam siklus hidup komponen.
OwCara memuat data dengan benar di dalam useEffect? Apa itu []?
Berikut adalah panduan yang baik tentang memuat data menggunakan
useEffect
. Cobalah untuk membacanya secara keseluruhan! Tidak sebesar itu. Tanda kurung,
[]
, mewakili array kosong, berarti bahwa efeknya tidak menggunakan nilai-nilai yang terlibat dalam aliran data Bereaksi, dan karena alasan ini penggunaan tunggal dapat dianggap aman. Selain itu, penggunaan array dependensi yang kosong adalah sumber kesalahan yang umum jika nilai tertentu sebenarnya digunakan dalam efek. Anda perlu menguasai beberapa strategi (terutama disajikan dalam bentuk
useReducer
dan
useCallback
) yang dapat membantu menghilangkan kebutuhan untuk ketergantungan daripada membuang ketergantungan ini secara tidak masuk akal.
▍ Apakah fungsi perlu ditentukan sebagai efek dependensi?
Disarankan bahwa fungsi yang tidak memerlukan properti atau keadaan diambil di luar komponen, dan fungsi-fungsi yang hanya digunakan oleh efek direkomendasikan untuk ditempatkan di dalam efek. Jika setelah itu efek Anda masih menggunakan fungsi-fungsi yang berada dalam ruang lingkup render (termasuk fungsi dari properti), bungkus dengan
useCallback
di mana mereka dideklarasikan, dan cobalah untuk menggunakannya lagi. Mengapa ini penting? Fungsi dapat “melihat” nilai dari properti dan status, sehingga mereka mengambil bagian dalam aliran data.
Berikut ini informasi lebih rinci tentang ini di FAQ kami.
▍ Mengapa suatu program kadang-kadang berakhir dalam satu lingkaran reload data yang tak berujung?
Ini bisa terjadi ketika memuat data dilakukan dalam efek yang tidak memiliki argumen kedua yang mewakili dependensi. Tanpa itu, efek dilakukan setelah setiap operasi rendering - yang berarti bahwa pengaturan negara akan menyebabkan efek tersebut ditarik kembali. Infinite loop juga dapat terjadi jika nilai yang selalu berubah ditunjukkan dalam array dependensi. Cari tahu nilainya seperti apa dengan menghapus dependensi satu per satu. Namun, menghapus dependensi (atau menggunakan
[]
dengan terburu-buru) biasanya merupakan pendekatan yang salah untuk menyelesaikan masalah. Sebagai gantinya, Anda harus menemukan sumber masalah dan benar-benar menyelesaikannya. Misalnya, fungsi dapat menyebabkan masalah serupa. Anda dapat membantu menyelesaikannya dengan meletakkannya di efek, memindahkannya di luar komponen, atau dengan membungkus
useCallback
. Untuk menghindari membuat beberapa objek, Anda bisa menggunakan
useMemo
.
▍ Mengapa terkadang kondisi lama terlihat di dalam efek atau properti lama ditemukan?
Efek selalu "melihat" properti dan status dari render di mana mereka dinyatakan. Ini membantu
mencegah kesalahan , tetapi dalam beberapa kasus dapat mengganggu pengoperasian komponen secara normal. Dalam kasus seperti itu, Anda dapat menggunakan tautan
ref
dapat
ref
secara eksplisit untuk bekerja dengan nilai-nilai tersebut (Anda dapat membaca tentang ini di akhir artikel yang disebutkan sebelumnya). Jika Anda berpikir bahwa Anda melihat properti atau keadaan dari render lama, tetapi jangan berharap ini, maka Anda mungkin telah melewatkan beberapa dependensi. Untuk belajar melihatnya, gunakan aturan linter ini. Dalam beberapa hari, itu akan menjadi seperti sifat kedua Anda. Juga, lihat jawaban
ini di FAQ kami.
Saya harap jawaban atas pertanyaan-pertanyaan ini bermanfaat bagi mereka yang membacanya. Sekarang mari kita bicara lebih banyak tentang
useEffect
.
Setiap render memiliki sifat dan statusnya sendiri.
Sebelum kita dapat membahas efeknya, kita perlu berbicara tentang rendering.
Berikut adalah komponen penghitung fungsional.
function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Lihatlah dari dekat garis
<p>You clicked {count} times</p>
. Apa yang dia maksud Apakah konstanta konstan entah bagaimana "mengamati" perubahan di negara dan apakah itu diperbarui secara otomatis? Kesimpulan ini dapat dianggap semacam ide pertama yang berharga dari seseorang yang mempelajari Bereaksi, tetapi itu bukan
model mental yang akurat tentang apa yang terjadi.
Dalam contoh kita,
count
hanyalah angka. Ini bukan semacam "ikatan data" ajaib, bukan semacam "objek pengamat" atau "proxy", atau apa pun. Sebelum kita adalah nomor lama yang baik, seperti ini:
const count = 42;
Selama output komponen pertama, nilai
count
diperoleh dari
useState()
adalah 0. Ketika kita memanggil
setCount(1)
, React memanggil komponen itu lagi.
count
waktu ini adalah 1. Dan seterusnya:
Bereaksi memanggil komponen setiap kali kita memperbarui negara. Akibatnya, setiap operasi rendering “melihat” nilainya sendiri dari status
counter
, yang, di dalam fungsi, adalah konstan.
Akibatnya, baris ini tidak melakukan operasi pengikatan data khusus:
<p>You clicked {count} times</p>
Ini hanya menyematkan nilai numerik dalam kode yang dihasilkan selama rendering. Nomor ini disediakan oleh React. Ketika kita memanggil
setCount
, React memanggil komponen lagi dengan nilai
count
berbeda. Bereaksi kemudian memperbarui DOM sehingga model objek dokumen cocok dengan output data terbaru selama rendering komponen.
Kesimpulan paling penting yang dapat ditarik dari ini adalah bahwa
count
adalah konstan di dalam render tertentu dan tidak berubah seiring waktu. Komponen yang dipanggil berulang kali berubah. Setiap render "melihat" nilai
count
sendiri, yang diisolasi untuk setiap operasi rendering.
Dalam materi
ini Anda dapat menemukan detail tentang proses ini.
Setiap render memiliki penangan acara sendiri.
Semuanya masih jelas. Bagaimana dengan penangan event?
Lihatlah contoh ini. Di sini, tiga detik setelah mengklik tombol, kotak pesan ditampilkan dengan informasi tentang nilai yang disimpan dalam
count
:
function Counter() { const [count, setCount] = useState(0); function handleAlertClick() { setTimeout(() => { alert('You clicked on: ' + count); }, 3000); } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <button onClick={handleAlertClick}> Show alert </button> </div> ); }
Misalkan saya melakukan urutan tindakan berikut:
- Saya akan membawa nilai
count
ke 3 dengan mengklik tombol Click me
. - Klik pada tombol
Show alert
. - Naikkan nilainya menjadi 5 sebelum batas waktu berakhir.
Meningkatkan nilai hitungan setelah mengklik tombol Perlihatkan tandaMenurut Anda, apa yang muncul di kotak pesan? Apakah 5 akan ditampilkan di sana, yang sesuai dengan nilai
count
pada saat timer dipicu, atau 3 - yaitu, nilai
count
pada saat tombol ditekan?
Sekarang Anda akan menemukan jawaban untuk pertanyaan ini, tetapi jika Anda ingin mengetahui semuanya sendiri -
ini adalah versi yang berfungsi dari contoh ini.
Jika apa yang Anda lihat tampaknya tidak dapat dipahami oleh Anda - ini adalah contoh yang lebih dekat dengan kenyataan. Bayangkan aplikasi obrolan di mana, dalam keadaan,
ID
penerima pesan saat ini disimpan, dan ada tombol
Send
. Dalam materi
ini , apa yang terjadi dipertimbangkan secara rinci. Bahkan, jawaban yang benar untuk pertanyaan tentang apa yang muncul di kotak pesan adalah 3.
Mekanisme untuk menampilkan kotak pesan "menangkap" keadaan pada saat tombol diklik.
Ada beberapa cara untuk mengimplementasikan versi perilaku lainnya, tetapi untuk sekarang kita akan membahas perilaku standar sistem. Ketika membangun model mental teknologi, penting untuk membedakan "jalan perlawanan paling tidak" dari semua jenis "pintu keluar darurat".
Bagaimana cara kerjanya?
Kami telah mengatakan bahwa nilai
count
adalah konstan untuk setiap panggilan khusus ke fungsi kami. Saya pikir layak untuk membahas hal ini secara lebih rinci. Intinya adalah bahwa fungsi kita dipanggil berkali-kali (satu kali untuk setiap operasi rendering), tetapi dengan masing-masing panggilan ini,
count
di dalamnya adalah konstan. Konstanta ini diset ke nilai tertentu (mewakili keadaan operasi rendering tertentu).
Perilaku fungsi ini bukan sesuatu yang istimewa untuk Bereaksi - fungsi biasa berperilaku dengan cara yang sama:
function sayHi(person) { const name = person.name; setTimeout(() => { alert('Hello, ' + name); }, 3000); } let someone = {name: 'Dan'}; sayHi(someone); someone = {name: 'Yuzhi'}; sayHi(someone); someone = {name: 'Dominic'}; sayHi(someone);
Dalam contoh
ini , variabel eksternal
someone
dipindahkan beberapa kali. Hal yang sama dapat terjadi di suatu tempat di dalam Bereaksi, keadaan komponen saat ini dapat berubah. Namun, di dalam fungsi
sayHi
ada
name
konstanta lokal yang dikaitkan dengan
person
dari panggilan tertentu. Konstanta ini bersifat lokal, oleh karena itu nilainya dalam panggilan fungsi yang berbeda diisolasi satu sama lain! Akibatnya, setelah batas waktu, setiap jendela pesan yang ditampilkan "mengingat" nilai
name
sendiri.
Ini menjelaskan bagaimana event handler kami menangkap nilai
count
ketika sebuah tombol diklik. Jika kita, bekerja dengan komponen, menerapkan prinsip yang sama, ternyata setiap render “melihat” nilai
count
sendiri:
Akibatnya, setiap render, pada kenyataannya, mengembalikan "versi" sendiri
handleAlertClick
. Masing-masing versi ini "mengingat" nilai
count
sendiri:
Itulah sebabnya dalam contoh
ini , penangan acara "milik" render tertentu, dan ketika Anda mengklik tombol, komponen menggunakan status
count
dari render ini.
Dalam setiap render tertentu, properti dan status selalu tetap sama. Tetapi jika operasi rendering yang berbeda menggunakan properti dan status mereka sendiri, hal yang sama terjadi dengan mekanisme apa pun yang menggunakannya (termasuk event handler). Mereka juga "milik" render tertentu. Oleh karena itu, bahkan fungsi asinkron di dalam event handler akan "melihat" nilai
count
sama.
Perlu dicatat bahwa dalam contoh di atas, saya menyematkan nilai
count
spesifik langsung ke fungsi
handleAlertClick
. Penggantian "mental" ini tidak akan merugikan kita, karena
count
konstan tidak dapat diubah dalam render tertentu. Pertama, itu adalah konstanta, dan kedua, itu angka. Aman untuk mengatakan bahwa seseorang juga dapat berpikir tentang makna lain, seperti objek, tetapi hanya jika kita menerima sebagai aturan untuk tidak membuat perubahan (mutasi) di negara bagian. Pada saat yang sama, kami puas dengan panggilan ke
setSomething(newObj)
dengan objek baru alih-alih mengubah yang sudah ada, karena dengan pendekatan ini keadaan milik render sebelumnya tidak tersentuh.
Setiap render memiliki efek sendiri.
Materi ini, seperti yang Anda tahu, dikhususkan untuk efek, tetapi kami belum membicarakannya. Sekarang kita akan memperbaikinya. Ternyata, bekerja dengan efek tidak jauh berbeda dari apa yang telah kita ketahui.
Pertimbangkan
contoh dari dokumentasi, yang sangat mirip dengan yang telah kita analisis:
function Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Sekarang saya punya pertanyaan untuk Anda. Bagaimana efek membaca nilai
count
terbaru?
Mungkin beberapa "pengikatan data" digunakan di sini, atau "objek pengamat" yang memperbarui nilai
count
di dalam fungsi efek? Mungkin
count
adalah variabel yang dapat berubah yang nilainya React set di dalam komponen kami, akibatnya efeknya selalu melihat versi terbarunya?
Tidak.
Kita sudah tahu bahwa dalam rendering komponen tertentu,
count
adalah konstan. Bahkan event handler “melihat” nilai
count
dari render tempat mereka “milik” karena fakta bahwa
count
adalah konstanta yang terletak dalam cakupan tertentu. Hal yang sama berlaku untuk efek!
Dan harus dicatat bahwa ini bukan jumlah variabel
count
yang entah bagaimana berubah di dalam efek "tidak berubah". Di depan kami adalah fungsi efek itu sendiri, yang berbeda di setiap operasi rendering.
Setiap versi "melihat" nilai
count
dari render yang menjadi "miliknya":
React mengingat fungsi efek yang kami sediakan, menjalankannya setelah mengatur ulang nilai-nilai di DOM, dan memungkinkan peramban untuk menampilkan gambar.Akibatnya, bahkan jika kita berbicara di sini tentang satu-satunya efek konseptual (memperbarui judul dokumen), itu diwakili dalam setiap render dengan fungsi baru, dan setiap fungsi efek "melihat" properti dan negara dari render khusus yang menjadi "milik".Efeknya, secara konseptual, dapat direpresentasikan sebagai bagian dari hasil rendering.Sebenarnya, ini tidak demikian (untuk memungkinkan komposisi kait ). , , , .
, , :
React:
:
- :
<p>You clicked 0 times</p>
. - , , :
() => { document.title = 'You clicked 0 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 0 times' }
.
, . , , - :
:
React:
:
- :
<p>You clicked 1 times</p>
. - , , :
() => { document.title = 'You clicked 1 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 1 times' }
.
…
, , , , «» .
. :
function Counter() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { console.log(`You clicked ${count} times`); }, 3000); }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
, ?
, . , , , . ! , , , , ,
count
.
.
: «, ! ?».
, ,
this.setState
, , . , ,
, , , :
componentDidUpdate() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); }
,
this.state.count
count
, , . , , , 5 , 5 .
, JavaScript-, , ,
, ,
setTimeout
, . , (React
this.state
, ), .
— , , «» , . , , , . , , . , , , , , ,
.
, ( , , - API ) , .
:
function Example(props) { useEffect(() => { setTimeout(() => { console.log(props.counter); }, 1000); });
, «» . ! . , .
, , - , , , , . ,
ref
,
.
, , , , , . , ( ), «» React-. , , . , .
, , , :
function Example() { const [count, setCount] = useState(0); const latestCount = useRef(count); useEffect(() => {
- React . React
this.state
. , ,
latestCount.current
. , . , , , .
?
, . , , «» .
:
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange); }; });
,
props
—
{id: 10}
,
{id: 20}
— . , :
- React
{id: 10}
. - React
{id: 20}
. - React
{id: 20}
.
( , , .)
, «» - , , «» - , . — , , , . .
React
, . , . . . :
- React
{id: 20}
. - .
{id: 20}
. - React
{id: 10}
. - React
{id: 20}
.
, «»
props
,
{id: 10}
, ,
props
{id: 20}
.
, …
— ?: « ( , , - API ) , ».
! « » , . , , :
, , … , «» , -,
{id: 10}
.
React . , , .
props
, .
,
React , .
.
, :
function Greeting({ name }) { return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
,
<Greeting name="Dan" />
, —
<Greeting name="Yuzhi" />
,
<Greeting name="Yuzhi" />
.
Hello, Yuzhi
.
, , . React, . , , .
$.addClass
$.removeClass
jQuery- ( — , «»), , CSS- React ( — , «»).
React DOM , . «» «».
.
useEffect
, React, .
function Greeting({ name }) { useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
useEffect
, , . , - , ! , «», «».
,
A
,
B
, —
C
, ,
C
. (, - ), .
, , , . ( ).
?
React
React DOM. DOM , React DOM, - .
, :
<h1 className="Greeting"> Hello, Dan </h1>
:
<h1 className="Greeting"> Hello, Yuzhi </h1>
React :
const oldProps = {className: 'Greeting', children: 'Hello, Dan'}; const newProps = {className: 'Greeting', children: 'Hello, Yuzhi'};
React ,
children
, DOM. ,
className
. :
domNode.innerText = 'Hello, Yuzhi';
- ? , , .
, , - :
function Greeting({ name }) { const [counter, setCounter] = useState(0); useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} <button onClick={() => setCounter(counter + 1)}> Increment </button> </h1> ); }
counter
.
document.title
name
,
name
.
document.title
counter
, .
React … ?
let oldEffect = () => { document.title = 'Hello, Dan'; }; let newEffect = () => { document.title = 'Hello, Dan'; };
— . React , , . ( .
name
.)
, , (
deps
),
useEffect
:
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
, React: «, , , ,
name
».
, , React :
const oldEffect = () => { document.title = 'Hello, Dan'; }; const oldDeps = ['Dan']; const newEffect = () => { document.title = 'Hello, Dan'; }; const newDeps = ['Dan'];
, , ! - - .
React
React — . , , , ,
useEffect
, , , . ( !)
function SearchResults() { async function fetchData() {
FAQ , . .
« !», — . : , , . , , , — , .
, , . , , , , . , . .
, , .
, React
, , React , .
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
—, , ,
[]
, , , , :
useEffect(() => { document.title = 'Hello, ' + name; }, []);
—. , «» , , .
, , , . , : «
setInterval
clearInterval
».
. , , ,
useEffect
, , ,
[]
. - , ?
function Counter() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <h1>{count}</h1>; }
, ,
.
, « , », . , , ,
setInterval
, . , ?
, — React , , . ,
count
, React , , , . — .
count
0.
setCount(count + 1)
setCount(0 + 1)
. , —
[]
,
setCount(0 + 1)
:
React, , , — .
count
— , ( ):
const count =
. React .
,. , , React , , . —
- .
React , . , , , .
, , , .
count
:
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
. , , — , .
count
,
count
,
setCount(count + 1)
:
,
setInterval
,
count
, . , .
,, , , . — , .
.
,
count
.
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
, ,
count
. ,
count
setCount
. , ,
count
. , ,
setState
:
useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(id); }, []);
« ». ,
count
- ,
setCount(count + 1)
.
count
- ,
count + 1
«» React. React
count
. , React — , , , .
setCount(c => c + 1)
. « React », , . « » , ,
.
, , , . React.
count
:
,.
,
setInterval
, ,
c => c + 1
.
count
. React .
Google Docs
, , — ? , , «», , . , Google Docs . . , .
, . . ,
setCount(c => c + 1)
, ,
setCount(count + 1)
, «»
count
. , ( — «»). « React» —
. .
( ) , Google Docs
. — , React . , , ( , , ) .
,
setCount(c => c + 1)
, . , . , , , , , .
setCount(c => c + 1)
.
useReducer
.
, :
count
step
.
setInterval
,
step
:
function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + step); }, 1000); return () => clearInterval(id); }, [step]); return ( <> <h1>{count}</h1> <input value={step} onChange={e => setStep(Number(e.target.value))} /> </> ); }
.
, React .
step
, . .
:
step
setInterval
—
step
. , , , ! , , , , , .
, , ,
setInterval
,
step
.
step
?
, ,
useReducer
.
,
setSomething(something => ...)
, , . «», , , .
step
dispatch
:
const [state, dispatch] = useReducer(reducer, initialState); const { count, step } = state; useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' });
.
: « , ?». , React ,
dispatch
. .
!
(
dispatch
setstate
useRef
, React , . — .)
, , , , .
step
. , . , . :
const initialState = { count: 0, step: 1, }; function reducer(state, action) { const { count, step } = state; if (action.type === 'tick') { return { count: count + step, step }; } else if (action.type === 'step') { return { count, step: action.step }; } else { throw new Error(); } }
, , , .
useReducer — -
, , , . , , ? , , API
<Counter step={1} />
. ,
props.step
?
, ! , :
function Counter({ step }) { const [count, dispatch] = useReducer(reducer, 0); function reducer(state, action) { if (action.type === 'tick') { return state + step; } else { throw new Error(); } } useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' }); }, 1000); return () => clearInterval(id); }, [dispatch]); return <h1>{count}</h1>; }
, . , , , , .
.
dispatch
. , , . .
, , . «» , , ? ,
dispatch
, React . . .
useReducer
«-» . , . , , , , .
, - , .
, , , :
function SearchResults() { const [data, setData] = useState({ hits: [] }); async function fetchData() { const result = await axios( 'https://hn.algolia.com/api/v1/search?query=react', ); setData(result.data); } useEffect(() => { fetchData(); }, []);
, .
, , . , , , , , , , , .
, , , , :
function SearchResults() {
, , :
function SearchResults() { const [query, setQuery] = useState('react');
, (, ), . .
, . , :
function SearchResults() {
.
? , « ». React, - .
getFetchUrl
,
query
, , , , . — ,
query
:
function SearchResults() { const [query, setQuery] = useState('react'); useEffect(() => { function getFetchUrl() { return 'https://hn.algolia.com/api/v1/search?query=' + query; } async function fetchData() { const result = await axios(getFetchUrl()); setData(result.data); } fetchData(); }, [query]);
.
, « React».
query
. , , , , . , , .
exhaustive-deps
eslint-plugin-react-hooks
, . , , .
.
, ?
. , , . , , .
? , . : React . . , « ». , , . , , , !
, , . ,
getFetchUrl
:
function SearchResults() { function getFetchUrl(query) { return 'https://hn.algolia.com/api/v1/search?query=' + query; } useEffect(() => { const url = getFetchUrl('react');
getFetchUrl
— , .
, «» , .
getFetchUrl
(, , ), :
function SearchResults() {
,
getFetchUrl
. , — . - , , . , , , .
— .
, , :
, . , , .
. ,
useCallback :
function SearchResults() {
useCallback
. : , -, , , .
, . (
'react'
'redux'
). , , ,
query
. , ,
query
,
getFetchUrl
.
,
query
useCallback
:
function SearchResults() { const [query, setQuery] = useState('react'); const getFetchUrl = useCallback(() => {
useCallback
query
, ,
getFetchUrl
,
query
:
function SearchResults() { const [query, setQuery] = useState('react');
useCallback
,
query
,
getFetchUrl
, , .
query
,
getFetchUrl
, . Excel: - , , , .
— , . , :
function Parent() { const [query, setQuery] = useState('react');
fetchData
Parent
query
,
Child
, .
?
, , , , . , , , , :
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, : « , , ,
useEffect
—
componentDidMount
componentDidUpdate
. !».
componentDidUpdate
:
class Child extends Component { state = { data: null }; componentDidMount() { this.props.fetchData(); } componentDidUpdate(prevProps) {
,
fetchData
— ! (, , , .) - , .
this.props.fetchData
prevProps.fetchData
. , , ?
componentDidUpdate(prevProps) { this.props.fetchData(); }
. . ( .) ,
fetchData
this.state.query
?
render() { return <Child fetchData={this.fetchData.bind(this, this.state.query)} />; }
this.props.fetchData !== prevProps.fetchData
true
, ,
query
! .
, , ,
query
Child
. , ,
query
,
query
:
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, , - , , .
, , .
this
, . , , , , - . ,
this.props.fetchData
, , , , , .
-
useCallback
. , , , . , .
useCallback
props.fetchData
.
,
useMemo
:
function ColorPicker() {
,
useCallback
, - . « », , , . , . ,
.
,
fetchData
( ), . , , . («
props.onComplete
, ?») , .
, :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . . — , :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.fetchData(this.props.id); } } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . , . ,
{id: 10}
,
{id: 20}
, , . , , , . .
, , . — , ,
async/await
( , - ) , ( , ).
,
async
-. (, , , , .)
, , ! .
, :
function Article({ id }) { const [article, setArticle] = useState(null); useEffect(() => { let didCancel = false; async function fetchData() { const article = await API.fetchArticle(id); if (!didCancel) { setArticle(article); } } fetchData(); return () => { didCancel = true; }; }, [id]);
, , , . , .
, , , , , . , , , . . — .
useEffect
, , , . React. ,
useEffect
.
, , « », . . , , , , «» , .
,
useEffect
, . — . — , , — , . , , , , API.
, ,
useFetch
, ,
useTheme
, . , ,
useEffect
. , , , .
, ,
useEffect
. — , . , . ?
Suspense React , , - ( : , , ) .
Suspense
, ,
useEffect
, , , - . , , , . , ,
, , .
Ringkasan
, . , , - , , , .
