React hooks: 04 - useState() qua ví dụ TodoList (2020)
HTML-код
- Опубликовано: 9 фев 2025
- Một ví dụ đơn giản nhưng rất chi tiết về cách sử dụng useState() hook trong functional component của react. Đây là một video trong chuỗi react hooks của mình.
Trong video này, mình cùng code với các bạn để chia sẻ một vài ý:
Phân tích components trước khi code.
Sử dụng useState() để quản lý danh sách todos.
Hướng dẫn cách render một list các items trong ReactJS.
Hướng dẫn remove một item ra khỏi list trong ReactJS.
🌐 Link tham khảo
Slide useState lab: drive.google.c...
Link source code: github.com/pau...
Introduction to react hooks: reactjs.org/do...
React hooks API reference: reactjs.org/do...
React hooks FAQ: reactjs.org/do...
#react_hooks #reactjs #usestate #easyfrontend
-----
💻 Easy Frontend 🎉
Nơi kiến thức lập trình web frontend (html/css/javascript/reactjs) được chia sẻ một cách đơn giản, dễ hiểu mà đặc biệt là vui 😊 Với những tài liệu (tutorial) được biên soạn một cách kĩ lưỡng để giúp các bạn developer mới có thể nắm bắt vấn đề một cách nhanh chóng và hiệu quả. Từ đó nâng dần khả năng coding của các bạn lên theo thời gian.
❤️ Ủng hộ mình làm videos thì đóng góp tại đây nhé:
Ủng hộ tôi: unghotoi.com/e...
MoMo/ZaloPay: 0901 309 729
Kết nối với mình:
🎉Facebook: / nvhauesmn
💻Github: github.com/pau...
💼 LinkedIn: / haunguyenmn
Cảm ơn các bạn đã xem video của mình!
Hãy like, share và subscribe nếu các bạn thấy hữu ích nhé! ❤️
Bạn nào code theo mình được thì điểm danh cho mình biết với nhé! 😉
em code được color box rồi anh ơi :v
Huy Cường Nguyễn =))) giờ tiếp todo list hen 😉
hóng anh dạy redux ạ
Dung Duong hehe cảm ơn em nha, nó sẽ tới sớm thôi nè, do a chỉ có mỗi tối hằng ngày để làm video thôi nên ko ra nhanh được 🙂
@@EasyFrontend dạ. cảm ơn anh ạ
Mong bạn update về khóa hoc React 2023 tren Udemy để mình đăng ký á.
hi bạn, mình cũng muốn update mà do bận quá
chắc mình sẽ tạo khóa mới luôn cho nó tiện theo dõi, cơ mà sẽ hơi lâu
tạm thời bạn tham khảo những bên khác giúp mình nhen, cảm ơn bạn nhiều nhiều ❤️
a dạy dễ hiểu ghê
Anh dảng bài nói chuyện cute thật luôn giáo viên oắt trường dạy vậy chắc 10, hết luôn
haha cảm ơn em nhiều nhé, tuy nhiên anh đc cái diễn giải thôi nè, còn kiến thức thì mình nghĩ thầy giỏi và chuyên sâu hơn mình nhiều nè 😉
Giờ mới biết kênh của anh. Cảm ơn anh đã chia sẻ. Anh dạy dễ hiểu quá !!
wohooo cảm ơn em nhiều nhé Đạt ơi 😊
E mới học FE và ms bắt đầu học React xem video của a thấy hay và dễ hiểu quá =))
yeah cảm ơn em nhiều nha, kênh còn nhiều nội dung hay lắm, em có thể tham khảo nhen hehe
www.ezfrontend.com/blog/tong-hop-tai-lieu-hay-tu-easy-frontend
Về phần auto Organize Imports thì VSCode nó sửa lại thành Shift + Alt + O rồi nha các bạn.
Coder Cyan Yeah cảm ơn bạn update thông tin cho mn nhé ❤️
Cảm ơn bạn vì thông tin này :D
may mắn khi được kết bạn với anh trên Facebook
function handleTodoClick có thể dùng hàm filter để viết ngắn lại thầy ah
vd : let newTodoList = todoList.filter(item => item.id !== todo.id)
Yeah hợp lý nha Lợi ơi, cảm ơn em nhiều nhen hehe 😉
Đang vừa ăn mì vừa cố gắng xem hết các bài giảng của anh
lol chăm học quá nè, ý mà trời đánh tránh bữa ăn, nên enjoy ăn uống xong hãy học nhen Lý 🙂
Video hay lắm a 🤘🤘
hehe cảm ơn em nhiều nhé Lâm 😍
A ơi đối tượng ColorBox.propTypes = {} để làm gì a nhỉ!!! :))
Có video giải thích về đối tượng này ko, a gửi link e với nhé
hi em, em tham khảo ở link này nhé
reactjs.org/docs/typechecking-with-proptypes.html
cơ bản nó giúp mình validate cái kiểu dữ liệu của props mình truyền vào em nhen hehe
E cảm ơn a nhé, e hiểu rồi
A ơi cho e hỏi e dùng filter thì không sao nhưng khi e thử clone mảng thì nó lại lỗi như thế này là sao ạ. TypeError: _components_TodoList__WEBPACK_IMPORTED_MODULE_2__.default is not iterable
hi Thiện, cái này có vẻ import có gì đó sai sai, em check lại thử nhen, a hk chắc lắm nhen, nếu hk đc thì chụp hình code post lên nhóm trao đổi easy frontend nhen Thiện 😉
@@EasyFrontend dạ vâng e cảm ơn Anh nhiều ạ
Dạ em có Code theo mà nó hiện lỗi ntn. Nhờ anh giúp em tí ạ
src\Components\TodoList\index.jsx
Line 15:19: 'onTodoCick' is assigned a value but never used no-unused-vars
à nó báo là em chưa dùng onTodoClick á Huy 😉
anh cho em hỏi là em tạo 1 file tên "todoList.js" sau đó export ra như a làm ở file "index.jsx" thì nó có khác gì nhau ko ạ, và em ko dùng PropTypes ạ
hi em, việc mình gom export vào một file index.js, nó sẽ giúp em import gọn hơn khi sử dụng
ví dụ: import { ComponentA, ComponentB } from '@/common'
thay vì
import ComponentA from '@/common/ComponentA'
import ComponentB from '@/common/ComponentB'
khi em có càng nhiều components chung một module thì em sẽ thấy cái này tiện lợi em nhen
@@EasyFrontend anh có thể giải thích kĩ hơn được ko ạ, em vẫn chưa hiểu lắm. Tại em thấy khi em để tên file là " .jsx " hay " .js " thì kết quả giao diện vẫn như nhau , a có thể giải thích kĩ hơn về sự khác nhau giữa 2 file này ko ạ
Note cho mấy bạn ko remove đc 'Unused import' như a Hậu nói thì :
bên Window nếu như bạn xài VSCode thì sẽ là Alt + Shift + O nhé . Hóng phần useCallback() + useMemo() quá a Hậu ơi :D
Tâm Phạm hehe a định nói sau phần useEffect() hehe, Tâm có đang gặp vấn đề gì vs useCallback hk Tâm? 😉
@@EasyFrontend e nghe nói phần useCallback & useMemo có thể cải thiện performance nhưng lại không biết dùng ở đâu & lúc nào cho thích hợp? mong a giải thích hoặc cho e keyword để tìm hiểu
sao mình không dùng filter array để filter out todo cho nhanh nhỉ? bản thân filter (.map, .reduce) nó trả về 1 array mới mà.
setTodoList(todoList.filter(td => td.id !== todo.id))
Duong Nguyen ❤️ Yeahhh, đây cũng là một giải pháp hoàn toàn hợp lệ nhé Dương. Xét về mặt tốt hơn thì cách bạn nói nó tốt hơn nhé 👍 Cảm ơn bạn Dương đã phát hiện nhen!
Yea. Mình góp ý thôi. Cám ơn bạn vì nội dung video khá hay.
mọi người cho mình hỏi, trong thực tế mình có viết code từ bên "component todoList" rồi mới viết sang "component App" như lúc render todo ko vậy?
hi Hưng ơi, mình nghĩ cái này thì ko có chuẩn, chỉ là ai thuận chiều nào làm chiều đó, top-down hoặc bottom-top :)
Top-down thì tiện hơn tí, có dữ liệu từ trên đổ xuống, khi render sửa lại UI là xong.
Bottom-top thì nó đơn giản lúc đầu, chỉ quan tâm làm UI, lúc sau gắn logic vào là xong.
Kiểu nào cũng đc, quan trọng là mình quen kiểu nào, xúc kiểu đó hehe
@@EasyFrontend em mới học react anh ạ, nên thấy anh code bottom-top thấy hay quá, ko lẽ học theo anhh ^^. mà anh rep nhanh nhỉ
Ủa mọi người, Khi xóa 1 phần tử trong cái todoList thì tại sao không xóa trực tiếp trên todoList luôn. Ví dụ: todoList.Spice(index,1)
mà tại sao phải tạo biến newTodoList clone từ todoList rồi mới xóa.
hi em, với state là kiểu dữ liệu dạng tham chiếu (object, array, ...) thì khi thay đổi, em phải thay đổi tham chiếu của nó bằng cách clone từ cái cũ ra cái mới rồi thay đổi nha, nếu em thay đổi trực tiếp lên tham chiếu cũ nó sẽ ko hiểu là em có thay đổi và ko trigger re-render, em hãy thử nhé 😉
@@EasyFrontend dạ, cám ơn anh.
E đang thắc mắc dòng 28 (TodoList). Khi mình bắt sự kiện onclick gọi hàm HandleClick vì sao phải bỏ trong arrow function ạ ? Nhờ anh Hậu và mọi người giải đáp ạ !
em tham khảo câu trả lời này nhé Phú
res.cloudinary.com/kimwy/image/upload/v1637369222/easyfrontend/arrow-function_kpwfaj.jpg
@@EasyFrontend Em cảm ơn anh Hậu. Kiến thức rất hữu ích ạ !!
Cám ơn câu hỏi và câu trả lời, mình cũng có thắc mắc giống vậy.
Nghe anh giải thích cách dùng của onTodoClick với handleClick em mới ngộ ra, trước giờ em không biết phải xử lý khi thay đổi state ở component con như thế nào, đành dùng hạ sách là copy component con bỏ qua phần gọi luôn :D
Yeahhhh cái này gọi là đã thông kinh mạch nè hihi, ngon lành Thịnh hen hihi 😍
Hay lắm anh, cảm ơn anh nhé.
hihi cảm ơn e nhiều nhé Thuận ❤️
Để xóa những dòng không sử dụng bên Window theo mặc định là Shift + Alt + o anh nha!
à vậy hở, cảm ơn e nha. A hk dùng windows, cứ ngỡ nó map 1-1 qua chứ 😅
hihi mà map 1-1 là gì vậy anh ?
Noras ah hihi, ý anh là nó map tương ứng phím này bên macos sẽ là 1 phím bên windows. Như Option bên mac sẽ là Alt bên windows chẳng hạn 🙂
Dạ hihi
Bên Window nếu như bạn xài VSCode thì sẽ là Alt + Shift + O. nhé
a ơi làm thế nào để sử dụng được chức năng auto import thế ạ? e mò thử mãi nhưng k đc
à cái đó thì nó tự có em nha, nếu ko đc thì em thử cái thêm Auto Import extension thử nha 😉
thầy ơi, em bị lỗi chỗ nào mà cứ click bất cứ item nào thì nó xoá cứ mặc định xoá id theo thứ tự 1-2-3 ạ.
hi Hùng, em post lên group facebook nha hehe 😉Chứ ở đây hk biét em code sao nên anh hk rõ nữa nè 😉
@@EasyFrontend dạ, tại em nhìn đề thầy cho xong tự nghĩ code rồi,code không ra rồi mới nhìn code thầy, mà khi code lại theo thầy thì e thấy vẫn như cũ. để em thử code lại theo thầy lần nữa xem sao
@@EasyFrontend em làm lại được rồi thầy ơi, em sai chỗ này 'onClick={()=>handleClick(todo) ' em truyền thẳng cái {handleClick} như thế này nên bị sai ạ.
anh ơi, sao mình phải cần 1 hàm handleClick chỉ để gọi lên thằng onTodoClick(todo), trong khi đó mình code thẳng onClick={() => onTodoClick(todo) luôn vậy anh?
à cái này cũng được em nha, nhưng lưu ý giúp anh check thêm onTodoClick ko bị undefined nhen, nếu ko em gọi onTodoClick() sẽ bị lỗi á.
Mục đích việc gọi hàm cũng là để handle mấy cái logic này riêng, khỏi để trên jsx rườm rà thôi à hehe
Em có thể đổi thành thế này nha Vũ: onClick={() => onTodoClick && onTodoClick(todo)}
@@EasyFrontend Dạ em cảm ơn anh! em "tay ngang" bay qua học lập trình, nhờ có kênh của anh mà em ngộ ra rất nhiều điều....
@@vutruongsinh3591 Yeah hay quá Vũ ơi, a rất vui khi biết đc nội dung có ích được cho em nè 😍, hi vọng sẽ giúp ích đc chút xíu nào đó cho công việc và học tập của em hihi
vì sao chỗ onClick trên thẻ li anh lại dùng arrow func vậy ạ, nó khác gì khi anh gọi handleClick(todo) ạ
cái này anh có trả lời cho nhiều bạn rồi, em tham khảo lại nha. Anh copy bên dưới.
-----
hi anh Hậu ạ, anh cho em hỏi chút là khi nào mình truyền vào 1 hàm và khi nào thì mình gọi một hàm ạ
VD: onClick={handleTodo}
onClick ={() => console.log('Hello')}
----
Trả lời:
hi Tuấn, cả 2 đều là truyền vào hàm, ko có cái nào là gọi hàm hết em nha
onClick={handleTodo} : cái này là truyền vào một tham chiếu hàm
onClick ={() => console.log('Hello')}: cái này là truyền vào một hàm mà hàm này được tạo ra khi gọi, mình gọi nó là inline function
cả 2 trường hợp này đều truyền vào function, ko có cái nào là gọi hàm nha em
---
tiếp đến là khi nào dùng cái nào
Cách 1:
- Tham chiếu tạo ra một lần và mỗi lần click thì gọi tới tham chiếu đó thôi.
--> Nên dùng cách này khi có thể
Cách 2:
- Mỗi lần click là nó sẽ tạo ra một hàm mới rồi mới thực thi (tham chiếu đc tạo ra mỗi lần click)
- Hạn chế sử dụng, nhưng vẫn có trường hợp buộc sử dụng là truyền tham số tuỳ biến vào hàm.
Ví dụ handleTodo() cần em truyền vào biến todo thì buộc phải dùng inline òi, tại hàm onClick ko cho em todo, em phải lấy chỗ khác truyền vào.
```js
function App() {
const [todoList, setTodoList] = useState([])
// ví dụ hàm này cần nhận vào todo
const handleTodo = (todo) => {}
// vậy làm sao truyền todo vào hàm handleTodo bây giờ, onClick thì nó cung cấp biến e: Event,
// chứ đâu có todo, nên buộc phải dùng inline function chỗ này òi
return (
{todoList.map(todo => (
handleTodo(todo)}>{todo.content}
))}
)
}
```
@@EasyFrontend cảm ơn anh nhiều ạ
Mình có thắc mắc là tất cả business logic của Todo item onlick có nên để dành riêng cho Todo Component xử lý hay không vì mình thấy App có hàm handleClick của Todo thấy nó bị phụ thuộc vào App quá nếu muốn sử dụng TodoList component qua project khác thì không làm dc với lại khi App gắn nhiều component con lên thì số lượng hàm sẽ nhiều và khó quản lý nếu để chung.
hi Bảo, ở đây có một số ý nhen:
1. Mình prefer tạo ra các dump/ui component hơn là smart/stateful component để có thể tái sử dụng ở nhiều nơi khác nhau.
2. Có nên đẩy logic lên App ko? À thật ra thì ko, thường logic sẽ được handle ở cái trang chứa các component này, chứ ko phải là đẩy lên App. Tại ở đây ko làm routings, nên lấy App làm trang chứa mấy components này thôi nè. 🙂
Anh ơi. sao e để
const newArray = [...todoList];
setTodoList(newArray.splice(index, 1)); => result lỗi dạ anh
còn e dùng cách filter thì result ra
const newArray = [...todoList];
setTodoList(newArray.filter(item => item.id !== todo.id));
Hà Tuyền Hi Tuyền ơi, chỗ setTodoList bạn làm chưa đúng nè. Hàm Splice nó sẽ trả về cái mảng chứa các phần tử bị remove, chứ hk phải là mảng hiện tại sau khi remove nhé.
Bạn đọc tham khảo thêm ở đây hen developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
Còn về cách xài filters là hoàn toàn hợp lệ nha Tuyền ơi! 🙂
@@EasyFrontend dạ, oke tks anh
Mình nghĩ dùng filter thì không cần clone 1 mảng mới ra vì bản thân thằng filter đã tạo ra 1 mảng mới rồi
Hi Anh. Cho em hỏi xíu vd trong trường hợp là . Có 1 page gồm 2 input và 1 button search. Nếu nhấn vào search thì call API lấy data Còn ko nhấn vào button thì ko hiên thị data.
Ý tưởng là
Sẽ có 2 state 1state filter là chứa 2 input search
1 state sẽ chứa data sau khi call API
1 effect có dependency filter thấy đổi thì sẽ chạy effect call API
Do useEffect lần đầu tiên nó vẫn chạy nên sẽ check thêm if filter.name || filter.email thì mới call API else ko call API
Khi click button search thì sẽ set state filter thôi.
Thường là như vậy phải ko Anh
yeah đúng òi nha Tiến ơi 😉
Cảm ơn A Hậu
hihi cảm ơn e nhé ❤️. Em có code theo được đươc hk Thuận? 🙂
@@EasyFrontend Dạ được anh !! Anh Hậu hướng dẫn quá chi tiết luôn mà hihii
Anh ơi mình dùng axios để remove 1 item, thì mình todoApi.remove(todo.id) là được đúng không anh (em làm như này vẫn chạy được), không cần phải truyền index
à em gọi API thì cần ID như vậy là đủ rồi em nhen, ko cần index nhé hehe
Sau khi gọi remove api xong thì em gọi lại API list để nó fetch list mới về là okie nhen hehe
@@EasyFrontend tks anh
tại sao mình không viết tất cả ở file Component , mà phải truyền qua truyền lại vậy anh
cho dễ quản lý thôi bạn, dự án thực tế sẽ có nhiều feature nên chia ra cho dễ
Em có một thắc mắc là sao k thêm 1 tham số là idx ở hàm map nữa, khi onClick thì mình xóa trực tiếp idx đó luôn đỡ phải mất công đi tìm :v
Ah ơi cái chỗ tìm index thì mình chỉ cần const index=todo.id là được mà ah nhỉ đâu cần dùng hàm findIndex đâu ạ :)
lol làm sao đc em ơi, ở đây vô tình anh chỉ để id là 1, 2, 3 ví dụ thôi, chứ id thật đâu có vậy =))) với chưa kể nó còn thay đổi nữa nha Dũng
@@EasyFrontend Anh ơi đoạn đó em dùng thế này vẫn ra liệu có được không ạ
const newItem = todoList.filter((p) => p.id !== todo.id);
setTodoList(newItem);
@@trandoan4526 à được em nhé, mình dùng cách này khi ko biết index của item cần remove.
Còn khi đã biết index thì dùng cách của anh cho lẹ nhen 😉
Dạ a ơi cho em hỏi khi nhấn ul.todo-list rồi tab ra thì nó sẽ tự động ra thẻ ul có class là dùng extension gì v a. Em dùng ko đc ạ
hi Tú ơi, để gõ được cái đó, em có thể gõ trong:
1. File HTML
2. File JS, mà để ý góc dưới bên trái, mình chọn ngôn ngữ Javascript React nha
🙂
có thể giải thích cái propTypes được không ạ. no có tác dụng gì. và defaulPropType nữa tại vì mấy bài trước không thấy a có nhắc nên hơi không hiểu
hi Glory,
1. PropTypes là thư viện giúp em check props đầu vào của component phải đúng kiểu dữ liệu em khai báo. Nếu ko đúng nó sẽ báo lỗi cho em, để em sửa lại cho đúng.
2. Default props là khi một prop ko required, thì buộc phải có default value. Vd user ko truyền props A thì em muốn xài giá trị mặc định nào cho props A đó 🙂
3. Vụ props types nó chỉ giúp em dưới local, phát hiện bugs sớm và xử lý nè 🙂
4. Ko khai báo props types nó vẫn chạy bình thường, nhưng nếu e truyền sai kiểu dữ liệu nó cũng ko báo lỗi cho em.
5. Thực tế là khuyến khích em nên dùng nhé vì những tác dụng đề cập ở trên, đồng thời em cũng biết component đó sử dụng những props gì, ko thôi em phải đọc hết code mới biết đc nó dùng những props gì 😎
Hi vọng là trả lời được thắc mắc của em 🙂
Anh ơi cho em hỏi là mình sử dụng hook cho toàn bộ project react native đc không anh
hi em ơi, a chưa làm với React Native nhiều, nên hk dám trả lời câu hỏi của em nè hihi
@@EasyFrontend Dạ em cảm ơn anh nha...Coi như luận văn kì này toang rồi anh ơi 🙉
Em không ctrl + option + o để tối ưu import được a ơi? cái short key này là do plugin nào của VS a nhỉ ?
nguyen canh trung hi Trung, em dùng Mac thì thử Shift Option O thử sao nhen 😉 Nếu ko đc e tìm từ khoá organize import trong vscode nha 🙂
@@EasyFrontend Shift Option O là chuẩn rồi a ạ
.
anh giải thích thêm về cái check propsTypes được không ạ.nó có tác dụng gì. vô dự án thực tế khi đi làm có cần phải check không. tại em thấy hơi thừa?
quy le cao Hi Quý, có một vài điểm mình nghĩ thế này:
1. PropTypes nó giúp bạn kiểm tra đúng loại dữ liệu khi dev. Bạn hãy thử thế này, khai báo object, mà truyền vào array xem sao. Lúc chạy lên nó sẽ báo lỗi ở console, điều này giúp mình phát hiện lỗi sớm.
2. Bạn nên có props, thỉnh thoảng bạn muốn biết component này có những props gì? Bạn làm thế nào? À vào code đọc nè. Nhưng nếu có phần khai báo này, bạn hoàn toàn có thể thấy đc ngay các props được dùng và giá trị mặc định của nó. 🙂
Đó là suy nghĩ của mình.
Hi vọng giải đáp đc thắc mắc của bạn! 🙂
cảm ơn a ạ
nam nam hihi cảm ơn Nam, e code theo được hk Nam?
a ơi e làm theo a rồi bị lỗi e search gg rồi mà ko dc ! help em với ! thank a
em bị lỗi gì vậy Tùng, em tổng hợp thông tin rồi post lên group fb để mn support em nha 😉
Dự án thực tế anh nói là trong khóa học react trên udemy phải k ạ? Hiện tại e mới thấy a update tới bài shopping cart trên udemy
hi Trang, cái shopping cart đó là phần dự án thực tế á em nhen hihi, a sẽ chỉ mọi người tổ chức từng module một trong dự án thực tế, xong sau đó apply vào xây dựng cái shopping card đó nhen 😉
@@EasyFrontend à, do em chưa có tiền đăng ký học nên hay vào udemy tham khảo lộ trình thôi anh :v
@@EasyFrontend sắp tới a dự định up lên về chủ đề gì của khóa học nhỉ, khi nào có tiền mua ủng hộ anh :v
Anh ơi tầm 8:31 ạ. Cái chỗ key = {todo.id}.
Em viết giống anh thì ở console nó hiện lên 1 cái error như này:
Warning: Encountered two children with the same key, `2`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted - the behavior is unsupported and could change in a future version.
Anh làm ơn giải thích giúp em với ạ ???
À em sửa thành
todos.map((todo, index) => (
)
Thì hết lỗi ạ
Nam Anh Phạm hi Anh, cái này là do một trong 2 lý do:
- Cái key bị trùng, tức todo.id bị trùng.
- Hoặc key bị null/undefined, em xem lại dữ liệu thử nhen hehe 😉
@@EasyFrontend Ui chuẩn luôn anh ơi. Em nhập bị trùng 1 cái id. Cảm ơn anh nhiều ạ !!!
nó ghi rõ ràng là 2 thằng nhỏ trùng key `2` luôn á @@
Để xóa 1 item e làm theo cách này được k ạ,
function handleRemoveItem(id) {
const newTodos = todos.filter((todo) => todo.id !== id);
setTodos(newTodos);
}
a có thể giải thích nên dùng cách như a hay là cách e làm ạ, vì trước giờ e xử lý xóa 1 item toàn như này.
hi Dũng, cả 2 cách điều được nha em.
Còn xài cái nào thì tuỳ tình huống nè.
Nếu biết index thì xoá kiểu anh cho gọn.
Nếu ko biết index mà biết id thì xoá như em sẽ tốt hơn.
Nên linh hoạt sử dụng nhen Dũng 🙂
@@EasyFrontend Dạ ok a, e cám ơn ạ
anh cho em hỏi "function handleTodoClick(todo)" ở App tại sao truyền tham số todo mà vẫn hiện ra todoList vậy ạ? em cảm ơn
hi Quang, xin lỗi là a chưa hiểu câu hỏi của em nè?
Việc cái hàm đó là để handle lúc click lên một todo.
Còn việc render cái todo list là riêng nè 🙂
A ơi. S lại đuôi file index. Jsx . E thấy họ đều để đuôi js .
cao cuong hi Cường ơi, hiện thì e dùng đuôi .js hay .jsx đều được nhé.
js: em chỉ định là file javascript
jsx: em chỉ định là file JSX, mà component của mình thì chính xác là JSX, khúc return trong component có html vs js trộn với nhau là JSX đó Cường.
Nên a khuyên dùng jsx hơn nhen.
Đó là ý kiến của anh thôi nha.
Nếu e thích để js thì cứ để nè 🙂
khi anh tạo thằng newTodoList bằng cách copy thằng todoList thì khi xóa thằng newTodoList, thằng todoList cũng bị thay đổi theo mà. Em nghĩ như thế thì việc copy này vô nghĩa.
hi Vinh, em hãy thử dưới local và xem thử nó có works ko nhé 😉
@@EasyFrontend ý em muốn hỏi là ý nghĩa của việc copy newTodoList = [...todoList] ấy anh
@@luuthevinh4048 À khi em làm việc với state trong reactjs thì em phải đảm bảo là immutable, tránh mutate trực tiếp lên state hiện tại, nó sẽ ko works.
Tức em đang có mảng A, em thay đổi trực tiếp lên mảng A, reactjs kiểm tra thấy ref của A cũ với A mới giống nhau --> ko render lại.
Tuy nhiên nếu em có mảng A, e muốn thay đổi nó, em clone ra mảng mới, lúc này cái ref mới của mảng A được tạo ra, khi đó reactjs nó mới hiểu và render cái A mới cho mình.
Tương tự khi làm việc với Redux cũng vậy nha Vinh 😉
@@EasyFrontend thanks anh
anh ơi cho e hỏi sao e cài simple react snippets rồi mà k dùng đc lệnh rsfp vậy ạ.
tu tran có khi nào mấy chậm ko ta? em gõ xong đợi một chút xíu xem nó có nhắc ko nhé Tú 🙂
Anh ơi, do đề bài yêu cầu "Render danh sách todos với dữ liệu được truyền từ component cha" nên mình mới lưu state ở App Component, lúc này gọi là global state đúng không anh?. Nếu không có yêu cầu đề bài thì em lưu state ở TodoList Component, không cần truyền props từ App xuống, giống bài ColorBox anh đã chỉ ạ. Anh ơi trong thực tế thì nên dùng cách nào ạ? Em cảm ơn anh nhiều ạ!
hi Tiến, trong thực tế mình luôn ưu tiên UI component nhen em.
Tức nó chỉ nhận dữ liệu từ props và render UI tương ứng, để tăng tính tái sử dụng và hạn chế số nơi can thiệp vào app logic.
Ở đây anh để state trên App vì cái này làm demo, chứ còn thực tế trên App chỉ chứa routings tới các features/pages thôi em nhen.
Ví dụ TodoList của mình, em mà đưa dữ liệu vào trong là nó sẽ ko linh hoạt được, dữ liệu bị cố định.
Còn ví dụ anh có page 1 list todo 1
page 2 show list todo 2
thì em đâu làm đc hen?
Cho nên hãy để TodoList nhận props dữ liệu từ thằng cha, nó cho gì render đó hehe
Nó ko quan tâm dữ liệu đó từ đâu, cha nó là ai, miễn cho đúng props yêu cầu là render thôi em nhen 😉
@@EasyFrontend Dạ em đã hiểu rồi ạ, anh giải thích rất dễ hiểu và chi tiết ạ, em rất thích xem video của anh ạ. Dạ em cảm ơn anh nhiều ạ, em chúc anh thật nhiều sức khỏe, có thêm nhiều video hay hơn nữa ạ.
dạ a cho e hỏi là thay vì mình truyền todo ra ngoài App thì mình có thể truyền index ra ngoài App. Tại sao a hông làm như vậy? có lí do gì hả a?? E cảm ơn a
Phúc Minh Hay quá Phúc, bạn đã phát hiện được vấn đề rồi đó.
Thông thường khi làm delete mình sẽ hay truyền index để remove cho lẹ. Và trong ví dụ này mình hoàn toàn có thể truyền thêm index để làm nhé!
Nhưng ở đây mình muốn demo cho các bạn một vài ý:
1. Ông todo list, ổng chỉ biết khi có todo đc click thì báo lên. Chứ hk biết là sẽ làm việc gì. Nên có thể một vài trường hợp mình hk có truyền index.
2. Trong trường hợp hk biết index, có cách nào vẫn remove được todo hay ko? Yeah vẫn làm được tốt nè.
Hi vọng giải đáp được thắc mắc của bạn. Nhưng cái bạn phát hiện là đúng rồi đó Phúc hehe ❤️
@@EasyFrontend Vâng a e đã hiểu hihi . Lại hóng video của a típ rùi hehe
này cho nhanh anh: const newTodoList = todos.filter(x => x.id !== todo.id);
Yeahhh hoàn toàn hợp lý nhé Nhựt 😉
Cho em hỏi nếu mình chuyển dữ liệu từ App vào trong TodoList component luôn thì sao anh ?
Hi Ken, nếu bạn chuyển dữ liệu trực tiếp vào TodoList thì bạn sẽ khó tái sử dụng lại được nè.
Ví dụ: HomePage muốn dùng TodoList chỉ show 6 items
ShopPage muốn show 12 items.
...
Mỗi trang có một nhu cầu show khác nhau, vậy bạn làm như thế nào?
Với nó còn có thể dính tới filters, pagination, ...
Nên nếu bạn đặt dữ liệu vào TodoList luôn thì coi như nó cứng ngắt ở đó, tất cả các nơi phải dùng chung giống như vậy.
Hi vọng giải đáp được thắc mắc của bạn 🙂
@@EasyFrontend e vừa định hỏi, mà thấy a tl rõ ràng quá rồi :D
anh ơi cho em hỏi phím t anh nói là ctrl+alt+O hả anh mong anh trả lời em cảm ơn anh
hi Trường, cái tổ hợp phím để tổ chức import trong vscode là:
- Windows: Shilf + Alt + O
- MacOS: Ctrl + Options + O
🙂
thanks anh ^^!
Bài này khi em map thằng todos em truyền thêm index khi map cho function handleClick(todo, index) thì khi bên thằng cha e lấy luôn được index ko cần dùng thằng findIndex để tìm index của phần tử trong mảng nữa. vậy tối ưu hơn a nhỉ :D
Yeah hợp lý nhé Minh 😍
@@EasyFrontend vâng ạ
Khi nào mới đến redux với routing vậy a :D
Khải Lâm hêh chắc phải tuần sau nữa á Lâm ơi! Tuần sau thì a sẽ nói nhiều về useEffect() hehee 😉
@@EasyFrontend chuẩn anh ơi, bọn em mới học nên anh dạy redux là hợp lý á
suck an amazing course !!! thank you so much, Can you help me how to use "ul.todo" and it became the ul tag with todo class?
Lâm Nguyễn à Lâm ơi, em dùng vscode nha, tắt chế độ gõ tiếng Việt, rồi gõ trong file html, ul.todo rồi nhấn tab nha Lâm hehe 😊
cảm ơn a
anh ơi, ở trong component TodoList. Chỗ event onClick tại sao mình phải viết onClick={() => handleTodoClick(todo)} mà không viết là onClick={handleTodoClick(todo)}.
Nếu không có "() =>" thì vừa vào nó sẽ log ra hết cả 3 items luôn. Tại sao lại vậy ạ, mình đã click nó đâu và sự khác biệt ở đây là gì? Cám ơn anh
hi Trực ơi, hai cái này nó khác nhau nhé
onClick={() => handleTodoClick(todo)}
() => handleTodoClick(todo): đây là một anonymous function, trong function này chỉ có một dòng code là handleTodoClick(todo).
Như vậy khi click, một hàm anonymous được tạo ra và thực thi hàm này.
onClick={handleTodoClick(todo)}
còn trường hợp này handleTodoClick(todo) là một lời gọi thực thi hàm và trả về kết quả gán về onClick.
Như vậy ko đúng, vì onClick cần nhận vào một function nha. 😉
a cho em hỏi vậy giữa 2 thằng này có khác nhau không ạ?
onClick={handleTodoClick} và onClick={ hanldeTodoClick() }
@@khanhhq2044 hóng a Hậu rep ạ