useState
useState
merupakan React Hook yang memungkinkan Anda untuk menambahkan state variable pada komponen anda.
const [state, setState] = useState(initialState);
Referensi
useState(initialState)
Panggil fungsi useState
di tingkat atas komponen Anda untuk mendeklarasikan sebuah state variable.
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...
Konvensi dalam menamai state variable adalah menggunakan pola [something, setSomething]
dengan array destructuring.
Lihat contoh lainnya di bawah ini.
Parameter
initialState
: Nilai awal pada sebuah state. Nilainya dapat berupa jenis apa saja, namun terdapat perilaku khusus untuk fungsi. Argumen ini diabaikan setelah rendering awal.- Jika Anda mengoper sebuah fungsi sebagai
initialState
, itu akan diperlakukan sebagai initializer function. Fungsi tersebut harus murni (pure), tidak boleh menerima argumen, dan harus mengembalikan nilai dengan tipe apa pun. React akan memanggil initializer function ketika menginisialisasi komponen, dan menyimpan nilai kembaliannya sebagai state awal. Lihat contoh lainnya di bawah ini.
- Jika Anda mengoper sebuah fungsi sebagai
Mengembalikan
useState
mengembalikan sebuah senarai dengan tepat dua nilai:
- State saat ini. Pada saat pertama kali render, itu akan cocok dengan
initialState
yang anda oper sebelumnya. - Fungsi
set
function yang memungkinkan Anda memperbarui state menjadi nilai yang berbeda dan memicu pembaruan ulang (re-render).
Peringatan
useState
merupakan sebuah Hook, sehingga Anda hanya dapat memanggilnya di level atas komponen Anda atau Hooks Anda sendiri. Anda tidak dapat memanggilnya di dalam perulangan atau kondisi. Jika Anda membutuhkannya, Anda dapat membuat komponen baru dan pindahkan state ke dalamnya.- Dalam Strict Mode, React akan memanggil fungsi inisialisasi Anda dua kali untuk membantu Anda menemukan kejadian yang tidak diharapkan. Hal ini hanya terjadi pada pengembangan dan tidak mempengaruhi produksi. Jika initializer function Anda murni (sebagaimana mestinya), ini seharusnya tidak mempengaruhi perilakunya. Hasil dari salah satu pemanggilan akan diabaikan.
Fungsi set
, seperti setSomething(nextState)
Fungsi set
yang dikembalikan oleh useState
memungkinkan Anda memperbarui state ke nilai yang berbeda dan memicu pembaruan ulang (re-render). Anda dapat mengoper state berikutnya secara langsung, atau sebuah fungsi yang mengkalkulasi dari state sebelumnya:
const [name, setName] = useState('Edward');
function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...
Parameters
nextState
: Nilai yang anda inginkan untuk menjadi state berikutnya. Ini dapat berupa nilai dari jenis apa pun, tetapi ada perilaku khusus untuk sebuah fungsi.- Jika Anda mengoper sebuah fungsi sebagai
nextState
, itu akan diperlakukan sebagai fungsi pembaruan (updater function). Fungsi ini harus murni (pure), hanya menerima state yang tertunda sebagai argumen satu-satunya, dan harus mengembalikan state berikutnya. React akan menempatkan fungsi pembaruan Anda dalam antrian dan memperbarui ulang komponen Anda. Selama render berikutnya, React akan mengkalkulasi state berikutnya dengan menerapkan semua pembaruan dalam antrian ke state sebelumnya Lihat contoh lainnya di bawah ini.
- Jika Anda mengoper sebuah fungsi sebagai
Returns
Fungsi set
tidak memiliki nilai kembali.
Peringatan
-
Fungsi
set
hanya memperbarui variabel state untuk render berikutnya. Jika Anda membaca variabel state setelah memanggil fungsiset
, Anda akan tetap mendapatkan nilai lama yang ada di layar sebelum panggilan Anda. -
Jika nilai baru yang Anda berikan identik dengan
state
saat ini, seperti yang ditentukan oleh perbandinganObject.is
, React akan melewatkan proses pembaruan ulang komponen dan anak-anaknya Ini merupakan sebulah optimisasi. Meskipun dalam beberapa kasus React mungkin masih perlu memanggil komponen Anda sebelum melewatkan anak-anaknya, ini seharusnya tidak mempengaruhi kode Anda. -
React pembaruan state berkelompok. Fungsi
set
akan memperbarui tampilan setelah semua event handler selesai dijalankan dan memanggil fungsiset
masing-masing. Hal ini mencegah terjadinya beberapa pembaruan ulang selama satu event. Dalam kasus yang jarang terjadi di mana Anda perlu memaksa React untuk memperbarui tampilan lebih awal, misalnya untuk mengakses DOM, Anda dapat menggunakanflushSync
. -
Memanggil fungsi
set
selama rendering hanya diperbolehkan dari dalam komponen yang sedang dirender saat ini. React akan membuang outputnya dan segera mencoba me-render kembali dengan state yang baru. Pola ini jarang dibutuhkan, tetapi bisa digunakan untuk menyimpan informasi dari render sebelumnya. See an example below. -
Pada Strict Mode, React akan memanggil fungsi updater Anda dua kali untuk membantu Anda menemukan kejadian yang tidak diharapkan. Ini hanya terjadi di lingkungan pengembangan dan tidak memengaruhi produksi. Jika fungsi updater Anda murni (seperti seharusnya), ini tidak akan memengaruhi perilakunya. Hasil dari salah satu panggilan akan diabaikan.
Penggunaan
Menambahkan state pada sebuah komponen
Memanggil useState
di tingkat atas komponen Anda untuk mendeklarasikan satu atau lebih state variables.
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...
Konvensi dalam menamai state variable adalah menggunakan pola [something, setSomething]
dengan array destructuring.
useState
mengembalikan sebuah senarai dengan tepat dua nilai:
- The current state of this state variable, initially set to the initial state you provided.
- The
set
function that lets you change it to any other value in response to interaction.
Untuk memperbarui tampilan layar, panggil fungsi set
dengan state berikutnya:
function handleClick() {
setName('Robin');
}
React akan menyimpan state berikutnya, me-render komponen Anda kembali dengan nilai baru, dan memperbarui antarmuka pengguna.
Example 1 of 4: Counter (number)
Dalam contoh ini, variabel state count
menyimpan sebuah angka. Dengan mengklik tombol, angka tersebut akan bertambah.
import { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> You pressed me {count} times </button> ); }
Memperbarui state berdasarkan state sebelumnya
Misalkan age
adalah 42
. Lalu handler ini memanggil setAge(age + 1)
sebanyak tiga kali:
function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
Namun, setelah satu kali klik, age
hanya akan menjadi 43
daripada 45
! Hal ini terjadi karena memanggil fungsi set
tidak memperbarui variabel state age
pada kode yang sudah dieksekusi. Oleh karena itu, setiap panggilan setAge(age + 1)
menjadi setAge(43)
.
Untuk memecahkan masalah ini, anda dapat mengoper sebuah fungsi pembaruan (updater function) pada setAge
daripada state berikutnya:
function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}
Here, a => a + 1
is your updater function. It takes the pending state and calculates the next state from it.
React menempatkan fungsi pembaruan Anda dalam sebuah antrian. Selanjutnya, selama render berikutnya, React akan memanggil fungsi-fungsi tersebut dalam urutan yang sama:
a => a + 1
akan menerima42
sebagai state yang tertunda dan mengembalikan43
sebagai state berikutnya.a => a + 1
akan menerima43
sebagai state yang tertunda dan mengembalikan44
sebagai state berikutnya.a => a + 1
akan menerima44
sebagai state yang tertunda dan mengembalikan45
sebagai state berikutnya.
Karena tidak ada pembaruan antrian lainnya, maka React akan menyimpan 45
sebagai state saat ini.
Secara konvensi, umumnya disepakati untuk memberi nama argumen state tertunda dengan huruf pertama dari nama variabel state, seperti a
untuk age
. Namun, Anda juga dapat memberinya nama seperti prevAge
atau sesuatu yang menurut Anda lebih jelas.
React mungkin akan memanggil pembaruan Anda dua kali pada saat pengembangan untuk memeriksa apakah mereka murni.
Deep Dive
Anda mungkin mendengar rekomendasi untuk selalu menulis kode seperti setAge(a => a + 1)
jika state yang Anda atur d
ikalkulasi dari state sebelumnya. Tidak ada masalah dengan itu, tetapi juga tidak selalu diperlukan.
Pada kebanyakan kasus, tidak ada perbedaan antara kedua pendekatan tersebut. React selalu memastikan bahwa untuk tindakan pengguna yang disengaja, seperti klik, variabel state age
akan diperbarui sebelum klik berikutnya. Ini berarti tidak ada risiko klik handler melihat age
yang “usang” di awal event handler.
Namun, jika Anda melakukan beberapa pembaruan dalam satu event, fungsi pembaruan dapat membantu. Mereka juga membantu jika mengakses variabel state itu sendiri merepotkan (Anda mungkin mengalaminya saat mengoptimalkan re-render).
Jika Anda lebih suka konsistensi daripada sintaks yang sedikit lebih panjang, masuk akal untuk selalu menulis fungsi pembaruan jika state yang Anda atur dikalkulasi dari state sebelumnya. Jika dihitung dari state sebelumnya dari beberapa variabel state yang lain, Anda mungkin ingin menggabungkannya menjadi satu objek dan menggunakan reducer.
Example 1 of 2: Mengoper fungsi pembaruan
Contoh ini menggunakan fungsi pembaruan, sehingga tombol “+3” berfungsi.
import { useState } from 'react'; export default function Counter() { const [age, setAge] = useState(42); function increment() { setAge(a => a + 1); } return ( <> <h1>Your age: {age}</h1> <button onClick={() => { increment(); increment(); increment(); }}>+3</button> <button onClick={() => { increment(); }}>+1</button> </> ); }
Mengupdate objek dan senarai di dalam state.
Anda dapat menempatkan objek dan senarai ke dalam state. Di React, state dianggap sebagai sesuatu yang hanya bisa dibaca, sehingga Anda harus menggantinya (replace) daripada mutasi (mutate) objek yang sudah ada. Misalnya, jika Anda memiliki objek form
di dalam state, jangan mutasi (mutate) secara langsung:
// 🚩 Don't mutate an object in state like this:
form.firstName = 'Taylor';
Instead, replace the whole object by creating a new one:
// ✅ Replace state with a new object
setForm({
...form,
firstName: 'Taylor'
});
Baca memperbarui objek pada state dan memperbarui senarai pada *state untuk belajar lebih lanjut.
Example 1 of 4: Form (objek)
Pada contoh ini, variabel state form
menampung sebuah objek. Setiap masukan memiliki pengendali perubahan yang memanggil setForm
dengan state berikutnya dari keseluruhan form. Spead syntax { ...form }
memastikan bahwa objek state diganti daripada dimutasi (mutated).
import { useState } from 'react'; export default function Form() { const [form, setForm] = useState({ firstName: 'Barbara', lastName: 'Hepworth', email: 'bhepworth@sculpture.com', }); return ( <> <label> First name: <input value={form.firstName} onChange={e => { setForm({ ...form, firstName: e.target.value }); }} /> </label> <label> Last name: <input value={form.lastName} onChange={e => { setForm({ ...form, lastName: e.target.value }); }} /> </label> <label> Email: <input value={form.email} onChange={e => { setForm({ ...form, email: e.target.value }); }} /> </label> <p> {form.firstName}{' '} {form.lastName}{' '} ({form.email}) </p> </> ); }
Menghindari membuat ulang state awal
React menyimpan state awal sekali dan mengabaikannya pada render berikutnya.
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...
Meskipun hasil dari createInitialTodos()
hanya digunakan untuk render awal, Anda tetap memanggil fungsi ini pada setiap render. Hal ini dapat menjadi pemborosan jika membuat senarai yang besar atau melakukan kalkulasi yang mahal
Untuk mengatasi hal tersebut, kamu dapat mengopernya sebagai fungsi initializer ke useState
sebagai gantinya:
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...
Perhatikan bahwa Anda mengoper createInitialTodos
, yang merupakan fungsi itu sendiri dan bukan createInitialTodos()
, yang merupakan hasil dari pemanggilannya. Jika Anda mengoper sebuah fungsi ke useState
, React hanya akan memanggilnya selama inisialisasi.
React dapat memanggil inisialisator Anda dua kali pada saat pengembangan untuk memeriksa apakah mereka murni.
Example 1 of 2: Mengoper fungsi inisialisasi
Contoh ini mengoper sebuah fungsi inisialisasi, sehingga fungsi createInitialTodos
hanya berjalan ketika inisalisasi. Ini tidak berjalan ketika komponen di-render ulang, seperti ketika Anda mengetikkan masukan.
import { useState } from 'react'; function createInitialTodos() { const initialTodos = []; for (let i = 0; i < 50; i++) { initialTodos.push({ id: i, text: 'Item ' + (i + 1) }); } return initialTodos; } export default function TodoList() { const [todos, setTodos] = useState(createInitialTodos); const [text, setText] = useState(''); return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => { setText(''); setTodos([{ id: todos.length, text: text }, ...todos]); }}>Add</button> <ul> {todos.map(item => ( <li key={item.id}> {item.text} </li> ))} </ul> </> ); }
Mereset state menggunakan kunci (key)
Anda sering melihat atribut key
saat me-render daftar. Namun, atribut ini juga memiliki tujuan lain.
Anda dapat mereset state komponen dengan memberikan key
yang berbeda pada komponen. Pada contoh ini, tombol Reset mengubah variabel state version
, yang kami oper sebagai key
pada Form
. Ketika key
berubah, React membuat ulang komponen Form
(dan semua komponen anaknya) dari awal, sehingga state-nya di reset.
Baca menjaga dan mereset state untuk mempelajari lebih lanjut.
import { useState } from 'react'; export default function App() { const [version, setVersion] = useState(0); function handleReset() { setVersion(version + 1); } return ( <> <button onClick={handleReset}>Reset</button> <Form key={version} /> </> ); } function Form() { const [name, setName] = useState('Taylor'); return ( <> <input value={name} onChange={e => setName(e.target.value)} /> <p>Hello, {name}.</p> </> ); }
Menyimpan informasi dari render sebelumnya
Biasanya, Anda akan memperbarui state pada event handler. Namun, dalam kasus yang jarang terjadi, Anda mungkin ingin menyesuaikan state sebagai respons terhadap rendering — misalnya, Anda mungkin ingin mengubah variabel state ketika prop berubah.
Dalam kebanyakan kasus, Anda tika memerlukannya:
- Jika nilai yang Anda butuhkan dapat dikomputasi sepenuhnya dari props saat ini atau state lain, , hapus state yang redundan tersebut. Jika Anda khawatir tentang komputasi ulang yang terlalu sering,
useMemo
Hook dapat membantu. - Jika Anda ingin mereset seluruh state komponen, berikan
key
yang berbeda pada komponen Anda. - Jika Anda bisa, perbarui semua state yang relevan pada event handler.
Dalam kasus yang jarang terjadi bahwa tidak satu pun dari yang disebutkan di atas berlaku, ada pola yang dapat Anda gunakan untuk memperbarui state berdasarkan nilai-nilai yang telah di-render, dengan memanggil fungsi set
ketika komponen Anda sedang di-render..
Berikut contohnya. Komponen CountLabel
ini menampilkan prop count
yang dioper kepadanya::
export default function CountLabel({ count }) {
return <h1>{count}</h1>
}
Misalkan Anda ingin menunjukan apakah penghitung telah meningkat atau menurun sejak perubahan terakhir. Prop count
tidak memberi tahu hal ini — Anda perlu menelusuri dari nilai sebelumnya. Tambahkan variabel state prevCount
untuk menelusurinya. Tambahkan variabel state lain bernama rend
untuk menampung apakah hitungan telah meningkat atau menurun. Bandingkan prevCount
dengan count
, dan jika tidak sama, perbarui prevCount
dan trend
. Sekarang Anda dapat menampilkan prop hitungan saat ini dan bagaimana ia telah berubah sejak render terakhir.
import { useState } from 'react'; export default function CountLabel({ count }) { const [prevCount, setPrevCount] = useState(count); const [trend, setTrend] = useState(null); if (prevCount !== count) { setPrevCount(count); setTrend(count > prevCount ? 'increasing' : 'decreasing'); } return ( <> <h1>{count}</h1> {trend && <p>The count is {trend}</p>} </> ); }
Perhatikan bahwa jika Anda memanggil fungsi set
saat rendering, itu harus berada dalam kondisi seperti prevCount !== count
, dan harus ada pemanggilan seperti setPrevCount(count)
di dalam kondisi tersebut. Jika tidak, komponen Anda akan di-render dalam perulangan hingga terjadi crash. Selain itu, Anda hanya dapat memperbarui state dari komponen yang sedang di-render seperti ini. Memanggil fungsi set
dari komponen lain selama rending adalah kesalahan. Terakhir, pemanggilan set
Anda harus memperbarui state tanpa mutasi — ini bukan berarti Anda dapat melanggar aturan fungsi murni.
Pola ini bisa sulit dipahami dan biasanya lebih baik untuk dihindari. Namun, ini lebih baik daripada memperbarui state dalam efek. Ketika Anda memanggil fungsi set
selamat render, React akan me-render ulang komponen tersebut segera setelah komponen Anda keluar dengan pernyataan return
, dan sebelum me-render anak-anak. Dengan begitu, anak-anak tidak perlu me-render dua kali. Sisa fungsi komponen Anda tetap akan dieksekusi (dan hasilnya akan dibuang). Jika kondisi Anda berada di bawah semua panggilan Hook, Anda dapat menambahkan return
lebih awal untuk memulai ulang render sebelumnya.
Troubleshooting
I’ve updated the state, but logging gives me the old value
Calling the set
function does not change state in the running code:
function handleClick() {
console.log(count); // 0
setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!
setTimeout(() => {
console.log(count); // Also 0!
}, 5000);
}
This is because states behaves like a snapshot. Updating state requests another render with the new state value, but does not affect the count
JavaScript variable in your already-running event handler.
If you need to use the next state, you can save it in a variable before passing it to the set
function:
const nextCount = count + 1;
setCount(nextCount);
console.log(count); // 0
console.log(nextCount); // 1
I’ve updated the state, but the screen doesn’t update
React will ignore your update if the next state is equal to the previous state, as determined by an Object.is
comparison. This usually happens when you change an object or an array in state directly:
obj.x = 10; // 🚩 Wrong: mutating existing object
setObj(obj); // 🚩 Doesn't do anything
You mutated an existing obj
object and passed it back to setObj
, so React ignored the update. To fix this, you need to ensure that you’re always replacing objects and arrays in state instead of mutating them:
// ✅ Correct: creating a new object
setObj({
...obj,
x: 10
});
I’m getting an error: “Too many re-renders”
You might get an error that says: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Typically, this means that you’re unconditionally setting state during render, so your component enters a loop: render, set state (which causes a render), render, set state (which causes a render), and so on. Very often, this is caused by a mistake in specifying an event handler:
// 🚩 Wrong: calls the handler during render
return <button onClick={handleClick()}>Click me</button>
// ✅ Correct: passes down the event handler
return <button onClick={handleClick}>Click me</button>
// ✅ Correct: passes down an inline function
return <button onClick={(e) => handleClick(e)}>Click me</button>
If you can’t find the cause of this error, click on the arrow next to the error in the console and look through the JavaScript stack to find the specific set
function call responsible for the error.
My initializer or updater function runs twice
In Strict Mode, React will call some of your functions twice instead of once:
function TodoList() {
// This component function will run twice for every render.
const [todos, setTodos] = useState(() => {
// This initializer function will run twice during initialization.
return createTodos();
});
function handleClick() {
setTodos(prevTodos => {
// This updater function will run twice for every click.
return [...prevTodos, createTodo()];
});
}
// ...
This is expected and shouldn’t break your code.
This development-only behavior helps you keep components pure. React uses the result of one of the calls, and ignores the result of the other call. As long as your component, initializer, and updater functions are pure, this shouldn’t affect your logic. However, if they are accidentally impure, this helps you notice the mistakes.
For example, this impure updater function mutates an array in state:
setTodos(prevTodos => {
// 🚩 Mistake: mutating state
prevTodos.push(createTodo());
});
Because React calls your updater function twice, you’ll see the todo was added twice, so you’ll know that there is a mistake. In this example, you can fix the mistake by replacing the array instead of mutating it:
setTodos(prevTodos => {
// ✅ Correct: replacing with new state
return [...prevTodos, createTodo()];
});
Now that this updater function is pure, calling it an extra time doesn’t make a difference in behavior. This is why React calling it twice helps you find mistakes. Only component, initializer, and updater functions need to be pure. Event handlers don’t need to be pure, so React will never call your event handlers twice.
Read keeping components pure to learn more.
I’m trying to set state to a function, but it gets called instead
You can’t put a function into state like this:
const [fn, setFn] = useState(someFunction);
function handleClick() {
setFn(someOtherFunction);
}
Because you’re passing a function, React assumes that someFunction
is an initializer function, and that someOtherFunction
is an updater function, so it tries to call them and store the result. To actually store a function, you have to put () =>
before them in both cases. Then React will store the functions you pass.
const [fn, setFn] = useState(() => someFunction);
function handleClick() {
setFn(() => someOtherFunction);
}