Cara Membuat Daftar Todo dengan React Hooks

React v16.7.0-alpha memperkenalkan Hooks, dan saya senang.

Apa Itu Hooks?

Mereka adalah fungsi yang memberi Anda fitur React seperti kait status dan siklus hidup tanpa kelas ES6.

Beberapa manfaat adalah

  • Mengisolasi logika stateful, membuatnya lebih mudah untuk diuji.
  • Berbagi logika stateful tanpa alat peraga render atau komponen tingkat tinggi.
  • Memisahkan masalah aplikasi Anda berdasarkan logika, bukan kait siklus proses.
  • Menghindari kelas ES6, karena mereka unik, sebenarnya bukan kelas, dan bahkan menjebak pengembang JavaScript yang berpengalaman.

Untuk detail lebih lanjut, lihat pengantar Hooks resmi React.

Mengadopsi Hooks Secara Bertahap

Pada saat penulisan, Hooks dalam versi alfa, dan API mereka dapat berubah kapan saja.

React 16.8.0 adalah rilis stabil pertama yang mendukung Hooks, dan ada lebih banyak tutorial dan kode contoh setiap hari. Namun, karena tidak ada rencana untuk menghapus kelas dari React dan Hooks akan bekerja dengan kode yang sudah ada, tim React merekomendasikan untuk menghindari "penulisan ulang yang besar". Sebaliknya, mereka menyarankan untuk berlatih Hooks dalam komponen non-kritis terlebih dahulu, kemudian menggunakannya sebagai pengganti kelas selanjutnya.

Mari Buat Daftar Todo

Daftar Todo adalah contoh yang paling sering digunakan karena alasan yang bagus - ini adalah latihan yang luar biasa. Saya merekomendasikan ini untuk bahasa atau perpustakaan apa pun yang ingin Anda coba.

Kami hanya akan melakukan beberapa hal

  • Tampilkan todos dengan gaya Desain Material yang bagus
  • Izinkan menambahkan todos melalui masukan
  • Hapus todos

Mendirikan

Berikut adalah tautan GitHub dan CodeSandbox.

git clone //github.com/yazeedb/react-hooks-todo cd react-hooks-todo npm install 

The mastercabang memiliki proyek selesai, sehingga checkout startcabang jika Anda ingin mengikuti.

git checkout start

Dan jalankan proyeknya.

npm start

Aplikasi harus berjalan localhost:3000, dan inilah UI awal kami.

Ini sudah diatur dengan material-ui untuk memberikan tampilan profesional pada halaman kita. Mari mulai menambahkan beberapa fungsi!

Komponen TodoForm

Tambahkan file baru src/TodoForm.js,. Inilah kode awalnya.

import React from 'react'; import TextField from '@material-ui/core/TextField'; const TodoForm = ({ saveTodo }) => { return (    ); }; export default TodoForm; 

Diberikan namanya, kita tahu tugasnya adalah menambahkan todos ke negara bagian kita. Ngomong-ngomong, inilah hook pertama kami .

useState

Lihat kode ini

import { useState } from 'react'; const [value, setValue] = useState(''); 

useStatehanyalah sebuah fungsi yang mengambil status awal dan mengembalikan sebuah array. Silakan console.log.

Indeks pertama array adalah nilai negara Anda saat ini, dan indeks kedua adalah fungsi pembaru.

Jadi kami menamainya dengan tepat valuedan setValuemenggunakan tugas penghancuran ES6.

useState dengan Formulir

Formulir kami harus melacak nilai masukan dan panggilan saveTodosaat mengirimkan. useStatedapat membantu kami dengan itu!

Perbarui TodoForm.js, kode baru dicetak tebal .

import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; const TodoForm = ({ saveTodo }) => { const [value, setValue] = useState(''); return (  { event.preventDefault(); saveTodo(value); }} >  { setValue(event.target.value); }} value={value} />  ); }; export default TodoForm; 

Kembali index.js, impor dan gunakan komponen ini.

// ... import TodoForm from './TodoForm'; // ... const App = () => { return ( Todos ); }; 

Sekarang nilai Anda sudah masuk, kirim (tekan enter).

useState With Todos

Kami juga membutuhkan negara untuk todos kami. Impor useStatemasuk index.js. Keadaan awal kita harus berupa array kosong.

import React, { useState } from 'react'; // ... const App = () => { const [todos, setTodos] = useState([]); // ... }; 

Komponen TodoList

Buat file baru bernama src/TodoList.js.

Edit: Terima kasih Takahiro Hata karena telah membantu saya pindah onClickke tempat yang benar!

import React from 'react'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; import ListItemText from '@material-ui/core/ListItemText'; import Checkbox from '@material-ui/core/Checkbox'; import IconButton from '@material-ui/core/IconButton'; import DeleteIcon from '@material-ui/icons/Delete'; const TodoList = ({ todos, deleteTodo }) => (  {todos.map((todo, index) => (      { deleteTodo(index); }} >     ))}  ); export default TodoList; 

Dibutuhkan dua alat peraga

  • todos: Larik todos. Kami mapmengatasinya masing-masing dan membuat item daftar.
  • deleteTodo: Clicking a todo’s IconButton fires this function. It passes the index, which will uniquely identify a todo in our list.

Import this component in your index.js.

import TodoList from './TodoList'; import './styles.css'; const App = () => { //... }; 

And use it in your App function like so

Adding Todos

Still in index.js, let’s edit our TodoForm’s prop, saveTodo.

 { const trimmedText = todoText.trim(); if (trimmedText.length > 0) { setTodos([...todos, trimmedText]); } }} />

Simply merge the existing todos with our new one, extra whitespace cut out.

We can add todos now!

Clearing the Input

Notice the input isn’t clearing after adding a new todo. That’s a bad user experience!

We can fix it with a small code change in TodoForm.js.

 { event.preventDefault(); saveTodo(value); setValue(''); }} />

Once a todo’s saved, set the form state to an empty string.

It’s looking good now!

Deleting Todos

TodoList provides each todo’s index, as it’s a guaranteed way to find the one we want to delete.

TodoList.js

 { deleteTodo(index); }} >

We’ll take advantage of that in index.js.

 { const newTodos = todos.filter((_, index) => index !== todoIndex); setTodos(newTodos); }} />

Whatever todos don’t match the provided index are kept and stored in state using setTodos.

Delete functionality is complete!

Abstracting Todos useState

I mentioned that Hooks are great for separating state and component logic. Here’s what that may look like in our todo app.

Create a new file called src/useTodoState.js.

import { useState } from 'react'; export default (initialValue) => { const [todos, setTodos] = useState(initialValue); return { todos, addTodo: (todoText) => { setTodos([...todos, todoText]); }, deleteTodo: (todoIndex) => { const newTodos = todos.filter((_, index) => index !== todoIndex); setTodos(newTodos); } }; }; 

It’s our same code from index.js, but separated! Our state management’s no longer tightly coupled to the component.

Now just import it.

import React from 'react'; import ReactDOM from 'react-dom'; import Typography from '@material-ui/core/Typography'; import TodoForm from './TodoForm'; import TodoList from './TodoList'; import useTodoState from './useTodoState'; import './styles.css'; const App = () => { const { todos, addTodo, deleteTodo } = useTodoState([]); return ( Todos   { const trimmedText = todoText.trim(); if (trimmedText.length > 0) { addTodo(trimmedText); } }} /> ); }; const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); 

And everything still works like normal.

Abstracting Form Input useState

We can do the same with our form!

Create a new file, src/useInputState.js.

import { useState } from 'react'; export default (initialValue) => { const [value, setValue] = useState(initialValue); return { value, onChange: (event) => { setValue(event.target.value); }, reset: () => setValue('') }; }; 

And now TodoForm.js should look like this.

import React from 'react'; import TextField from '@material-ui/core/TextField'; import useInputState from './useInputState'; const TodoForm = ({ saveTodo }) => { const { value, reset, onChange } = useInputState(''); return (  { event.preventDefault(); saveTodo(value); reset(); }} >   ); }; export default TodoForm; 

And we’re all done! Hope you enjoyed, until next time!