Controlled & Uncontrolled Inputs
Controlled input
When you add value={formData.title} , the input’s value is always tied to React state. Whatever you type → triggers onChange → updates state → React re-renders input with new value. React is the single source of truth. Example:
If you do not have onChange handler, you will run into a warning:
We made this a controlled component by setting the `value` prop to the `title` state. But with a controlled component, you need to make sure that you upate that state whenever you type into the input.
Uncontrolled input
When you don’t add value={...} , the browser itself manages the input’s internal value. You can still type text, submit forms, and even read the value later (e.g. e.target.value in onChange ). React does not directly control what’s inside the box — it only reacts when you ask (via events or refs). Your code:
This is an uncontrolled input.
The browser shows what you type. Each keystroke triggers handleChange, where you probably do something like setFormData({ ...formData, [e.target.name]: e.target.value }). So React still knows the value (in state), but the UI itself isn’t locked to state. Why can you still submit and save?
Because the form submission uses the current DOM input value (e.target.value ) or your state that gets updated inside onChange . Both ways work:
If you read directly from state → your handleChange has been updating it. If you read directly from the <input> element on submit → the browser kept track of the typed value. formData or separate form elements
Collecting separate form elements
You should see the form with all the fields.
We have our inputs as their own state, however, you may be creating a form with many fields. You could create a single state object to hold all the form values. This way, you only need to update one state object instead of multiple states. We will look at that next.
Props Drilling
Truyền Props sẽ bắt đầu phức tạp khi mà:
có nhiều hơn 2-3 lớp components có nhiều props cần phải truyền lên hoặc xuống deleteNotes truyền từ App → NoteList → Note để gọi setNotes truyền từ App → NoteForm để cập nhật state trong handleSave handleChange và handleSave xử lý form trong NoteForm rồi cập nhật notes ở trên Okay, so we have our notes app, but the notes are not persisting. If we refresh the page, the notes are gone. We need to save the notes to local storage so they persist. To do this, we can use the localstorage API along with a hook called `useEffect`.
Form Submit
Sau khi submit form, notes sẽ thay đổi state, dẫn đến việc cập nhật UI.
Đó là lý do cần khai báo notes và setNotes ở App.jsx, rồi sau đó truyền xuống cho NoteForm.jsx xử lý, mutate notes.
We don't simply do notes.push(newNote) because we want to keep the notes state immutable.
SO we are using the spread operator to create a new array with the new note at the top.
If you wanted the new note at the bottom, you could do setNotes([...notes, newNote]) .
Collapsible Form
Conditional inline Styling
Delete Notes & Mutating Objects with filter()
Cách 1: Truyền thẳng một giá trị mới như thầy
Ở đây, notes chính là biến state hiện tại (giống như bạn đọc notes trực tiếp từ useState).
Bạn tính ra một array mới bằng filter, rồi React set state thành array đó.
Có thể gặp bug nếu nhiều setNotes chạy liên tiếp trong cùng một render cycle, vì notes lúc đó có thể đã “cũ”.
Cả 2 lần đều dùng chung cái notes ban đầu, nên cuối cùng chỉ xóa được 1 cái, chứ không phải cả 2.
Cách 2: Truyền một callback function
Ở đây, bạn không truyền giá trị, mà truyền một hàm. React sẽ tự động gọi hàm này, và truyền giá trị state hiện tại (notes) vào tham số đầu tiên, ở đây là prevNotes. Kết quả return từ hàm (prevNotes.filter(...)) sẽ được React dùng để cập nhật state mới. Với cách này, React đảm bảo rằng nó luôn lấy state mới nhất để truyền vào callback.
React sẽ chắc chắn mỗi lần callback nhận prevNotes mới nhất, nên xóa được cả 2 như mong muốn.