200 byte untuk pengelolaan status komponen Bereaksi
- Bereaksi kait : itu semua yang diperlukan untuk mengelola negara.
- ~ 200 byte , min + gz.
- Familiar API : Cukup gunakan Bereaksi seperti biasa.
- Minimum API : lima menit sudah cukup untuk mengetahuinya.
- Ditulis dalam TypeScript untuk memberikan inferensi tipe otomatis.
Pertanyaan utamanya adalah: apakah paket ini lebih baik daripada Redux? Baiklah ...
- Dia kurang. Ini 40 kali lebih kecil.
- Dia lebih cepat. Mengisolasi masalah kinerja tingkat komponen.
- Lebih mudah dipelajari. Bagaimanapun, Anda harus dapat menggunakan kait Bereaksi dan konteks, mereka keren.
- Lebih mudah diintegrasikan. Hubungkan satu komponen pada satu waktu tanpa memutus kompatibilitas dengan perpustakaan Bereaksi lainnya.
- Lebih mudah untuk diuji. Menguji reduksi secara terpisah adalah buang-buang waktu, sederhanakan menguji komponen Bereaksi sendiri.
- Ini lebih sederhana dalam hal mengetik. Ini ditulis untuk memaksimalkan penggunaan inferensi tipe.
- Dia minimalis. Ini hanya React.
Contoh kode
import React, { useState } from "react" import { createContainer } from "unstated-next" import { render } from "react-dom" function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment } } let Counter = createContainer(useCounter) function CounterDisplay() { let counter = Counter.useContainer() return ( <div> <button onClick={counter.decrement}>-</button> <span>{counter.count}</span> <button onClick={counter.increment}>+</button> </div> ) } function App() { return ( <Counter.Provider> <CounterDisplay /> <CounterDisplay /> </Counter.Provider> ) } render(<App />, document.getElementById("root"))
Sikap terhadap yang tidak disebutkan
Saya (Jamie Kyle - kira-kira Per.) Pertimbangkan perpustakaan ini sebagai penerus Unstated . Saya melakukan Unstated karena saya yakin bahwa Bereaksi sendiri melakukan pekerjaan besar dalam mengelola negara, dan tidak memiliki mekanisme sederhana untuk memisahkan keadaan umum dan logika. Oleh karena itu, saya membuat Unstated sebagai solusi "minimum" untuk masalah ini.
Dengan munculnya kait, Bereaksi telah menjadi jauh lebih baik dalam hal menyoroti keadaan umum dan logika. Jauh lebih baik dari sudut pandang saya, Unstated telah menjadi abstraksi yang tidak perlu.
BUKAN KURANG , saya percaya bahwa banyak pengembang tidak tahu cara memisahkan logika dan keadaan umum aplikasi menggunakan React hooks. Ini mungkin semata-mata karena kurangnya kualitas dokumentasi dan kelembaman komunitas, tetapi saya percaya bahwa API yang jelas dapat memperbaiki kekurangan ini.
Unstated Next adalah API ini. Alih-alih menjadi "API Minimum untuk berbagi negara dan logika di Bereaksi," sekarang memiliki "API Minimum untuk memahami cara berbagi keadaan dan logika di Bereaksi."
Saya sangat suka Bereaksi, saya ingin Bereaksi berkembang. Saya lebih suka bahwa komunitas meninggalkan penggunaan perpustakaan eksternal untuk mengelola negara seperti Redux, dan akhirnya mulai menggunakan alat yang dibangun menjadi Bereaksi dengan kekuatan penuh.
Jika, alih-alih menggunakan Unstated, Anda hanya menggunakan React - Saya akan menyambut ini. Tulis tentang itu di blog Anda! Bicara tentang itu di konferensi! Bagikan pengetahuan Anda dengan komunitas.
Panduan Tidak Tercantum-berikutnya
Jika Anda belum terbiasa dengan React hooks, saya sarankan Anda berhenti membaca dan membaca
dokumentasi yang sangat baik di situs web Bereaksi .
Jadi, dengan bantuan kait Anda dapat menulis sesuatu seperti komponen ini:
function CounterDisplay() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return ( <div> <button onClick={decrement}>-</button> <p>You clicked {count} times</p> <button onClick={increment}>+</button> </div> ) }
Jika komponen logika perlu digunakan di beberapa tempat, itu bisa diambil
ke dalam pengait khusus yang terpisah:
function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment } } function CounterDisplay() { let counter = useCounter() return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> </div> ) }
Tetapi apa yang harus dilakukan ketika Anda membutuhkan kondisi umum, dan bukan hanya logika?
Konteksnya berguna di sini:
function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment } } let Counter = createContext(null) function CounterDisplay() { let counter = useContext(Counter) return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> </div> ) } function App() { let counter = useCounter() return ( <Counter.Provider value={counter}> <CounterDisplay /> <CounterDisplay /> </Counter.Provider> ) }
Itu luar biasa dan luar biasa; semakin banyak orang menulis dengan gaya ini, semakin baik.
Namun, ada baiknya menambahkan sedikit lebih banyak struktur dan kejelasan sehingga API mengekspresikan niat Anda dengan sangat jelas.
Untuk melakukan ini, kami menambahkan fungsi createContainer()
, sehingga Anda dapat memperlakukan kait khusus Anda sebagai "wadah", sehingga API kami yang jelas dan jelas tidak mungkin digunakan secara salah.
import { createContainer } from "unstated-next" function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment } } let Counter = createContainer(useCounter) function CounterDisplay() { let counter = Counter.useContainer() return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> </div> ) } function App() { return ( <Counter.Provider> <CounterDisplay /> <CounterDisplay /> </Counter.Provider> ) }
Bandingkan teks komponen sebelum dan sesudah perubahan kami:
- import { createContext, useContext } from "react" + import { createContainer } from "unstated-next" function useCounter() { ... } - let Counter = createContext(null) + let Counter = createContainer(useCounter) function CounterDisplay() { - let counter = useContext(Counter) + let counter = Counter.useContainer() return ( <div> ... </div> ) } function App() { - let counter = useCounter() return ( - <Counter.Provider value={counter}> + <Counter.Provider> <CounterDisplay /> <CounterDisplay /> </Counter.Provider> ) }
Jika Anda menulis dalam TypeScript (dan jika tidak, saya sangat menyarankan Anda membiasakan diri dengannya), Anda juga akan mendapatkan inferensi jenis yang lebih baik. Jika kait khusus Anda diketik dengan kuat, output dari semua tipe lainnya akan bekerja secara otomatis.
API
createContainer(useHook)
import { createContainer } from "unstated-next" function useCustomHook() { let [value, setValue] = useState() let onChange = e => setValue(e.currentTarget.value) return { value, onChange } } let Container = createContainer(useCustomHook)
<Container.Provider>
function ParentComponent() { return ( <Container.Provider> <ChildComponent /> </Container.Provider> ) }
Container.useContainer()
function ChildComponent() { let input = Container.useContainer() return <input value={input.value} onChange={input.onChange} /> }
useContainer(Container)
import { useContainer } from "unstated-next" function ChildComponent() { let input = useContainer(Container) return <input value={input.value} onChange={input.onChange} /> }
Kiat
Kiat # 1: Menggabungkan Kontainer
Karena kita berurusan dengan kait khusus, kita dapat menggabungkan wadah di dalam kait lain.
function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment, setCount } } let Counter = createContainer(useCounter) function useResettableCounter() { let counter = Counter.useContainer() let reset = () => counter.setCount(0) return { ...counter, reset } }
Kiat # 2: Gunakan Kontainer Kecil
Kontainer sebaiknya dibuat kecil dan jelas difokuskan pada tugas tertentu. Jika Anda memerlukan logika bisnis tambahan dalam wadah - keluarkan operasi baru dalam kaitan terpisah, dan biarkan negara disimpan dalam wadah.
function useCount() { return useState(0) } let Count = createContainer(useCount) function useCounter() { let [count, setCount] = Count.useContainer() let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) let reset = () => setCount(0) return { count, decrement, increment, reset } }
Kiat # 3: Optimalisasi Komponen
Tidak ada "optimasi" terpisah untuk yang unstated-next
, metode yang biasa untuk mengoptimalkan komponen Bereaksi sudah cukup.
1) Optimalisasi subtree berat dengan memisahkan komponen.
Kepada:
function CounterDisplay() { let counter = Counter.useContainer() return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> <div> <div> <div> <div> </div> </div> </div> </div> </div> ) }
Setelah:
function ExpensiveComponent() { return ( <div> <div> <div> <div> </div> </div> </div> </div> ) } function CounterDisplay() { let counter = Counter.useContainer() return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> <ExpensiveComponent /> </div> ) }
2) Optimalisasi operasi berat dengan hook useMemo ()
Kepada:
function CounterDisplay(props) { let counter = Counter.useContainer()
Setelah:
function CounterDisplay(props) { let counter = Counter.useContainer()
3) Kurangi jumlah rendering ulang menggunakan React.memo () dan useCallback ()
Kepada:
function useCounter() { let [count, setCount] = useState(0) let decrement = () => setCount(count - 1) let increment = () => setCount(count + 1) return { count, decrement, increment } } let Counter = createContainer(useCounter) function CounterDisplay(props) { let counter = Counter.useContainer() return ( <div> <button onClick={counter.decrement}>-</button> <p>You clicked {counter.count} times</p> <button onClick={counter.increment}>+</button> </div> ) }
Setelah:
function useCounter() { let [count, setCount] = useState(0) let decrement = useCallback(() => setCount(count - 1), [count]) let increment = useCallback(() => setCount(count + 1), [count]) return { count, decrement, increment } } let Counter = createContainer(useCounter) let CounterDisplayInner = React.memo(props => { return ( <div> <button onClick={props.decrement}>-</button> <p>You clicked {props.count} times</p> <button onClick={props.increment}>+</button> </div> ) }) function CounterDisplay(props) { let counter = Counter.useContainer() return <CounterDisplayInner {...counter} /> }
Migrasi dengan unstated
Saya sengaja menerbitkan perpustakaan ini sebagai paket terpisah karena keseluruhan API benar-benar baru. Oleh karena itu, Anda dapat menginstal kedua paket secara paralel dan bermigrasi secara bertahap.
Bagikan kesan Anda tentang transisi ke yang unstated-next
, karena selama beberapa bulan ke depan saya berencana untuk melakukan dua hal berdasarkan informasi ini:
- Pastikan
unstated-next
memenuhi semua kebutuhan pengguna yang unstated
. - Pastikan bahwa untuk yang
unstated
dinyatakan ada proses migrasi yang jelas dan singkat ke yang unstated-next
.
Mungkin saya akan menambahkan beberapa API ke perpustakaan lama atau baru untuk membuat hidup lebih mudah bagi pengembang. Adapun unstated-next
, saya berjanji bahwa API yang ditambahkan akan seminimal mungkin, dan saya akan melakukan yang terbaik untuk menjaga perpustakaan tetap kecil.
Di masa depan, saya mungkin akan unstated-next
porting kode unstated-next
kembali ke unstated
sebagai versi utama baru. unstated-next
masih akan tersedia sehingga Anda dapat menggunakan unstated@2
dan unstated-next
dalam proyek yang sama secara paralel. Kemudian, ketika Anda menyelesaikan migrasi, Anda dapat meningkatkan ke unstated@3
dan menghapus unstated-next
(tentu saja, memperbarui semua impor ... harus ada cukup pencarian dan ganti).
Meskipun ada perubahan dramatis dalam API, saya harap saya dapat memberi Anda migrasi semudah mungkin. Saya akan senang setiap komentar tentang apa yang bisa dilakukan dengan lebih baik.
Referensi