Todolist with useState() | Xây dựng ứng dụng todolist | React hooks
ฝัง
- เผยแพร่เมื่อ 7 ก.พ. 2025
- 👉 Xem Lộ Trình Học: fullstack.edu....
👉 Đăng Ký Học Offline Tại F8: short.f8team.d...
Video này chúng ta sẽ tiếp tục tìm hiểu về Todolist with useState() | Xây dựng ứng dụng todolist | React hooks
Trong bài này chúng ta sẽ đi làm thêm 1 ví dụ Todolist rồi bài sau học sang useEffect() hook nhé anh em.
#hoclaptrinh #hoclaptrinhmienphi #javascript #reactjs #frontend #backend #devops #f8
-------
☻ Phần mềm sử dụng trong video:
Công cụ dịch Tiếng Anh: bit.ly/2Wsuhet
Công cụ đo đạc giao diện web: s.net.vn/D8kL
Công cụ viết CV xin việc chuyên nghiệp: mycv.vn
--------------
☻ Khóa học lập trình web MIỄN PHÍ:
Kiến thức nhập môn: fullstack.edu....
Xây dựng giao diện với HTML, CSS: fullstack.edu....
Xây dựng web responsive: fullstack.edu....
Lập trình Javascript cơ bản: fullstack.edu....
Lập trình Javascript nâng cao: fullstack.edu....
Làm việc với Terminal & Ubuntu: fullstack.edu....
Xây Dựng Website với ReactJS: fullstack.edu....
Xây dựng web với Node & Express: fullstack.edu....
HTML, CSS tips: fullstack.edu....
Ứng dụng cảnh báo khi sờ lên mặt: fullstack.edu....
Xem thêm tại: fullstack.edu....
-------------------------------------
F8 Official
(c) Sơn Đặng
Website: fullstack.edu.vn
Facebook cá nhân: / sondnf8
Nhóm Học Lập Trình Web: / f8official
Email: contact@fullstack.edu.vn
© Bản quyền thuộc về Channel F8 Official ☞ Do not Reup
© Nghiêm cấm sử dụng video nhằm mục đích thương mại dưới mọi hình thức.
Trong bài này chúng ta sẽ đi làm thêm 1 ví dụ Todolist rồi bài sau học sang useEffect() hook nhé anh em. Bài tập: Anh em xây dựng chức năng xóa cho Todolist nữa nhé 😍😍
anh ơi anh chữa bài chức năng xoá được ko anh
Khả năng phân tích và truyền đạt của anh này cao hơn nhiều so với đa số các giảng sư đại học mà tôi đã từng kinh qua, cả tây lẫn ta!
Đã học và hiểu. Hay quá thầy Sơn ơi
import { useState } from "react";
const JOB_KEY = "JOB_LIST";
function App() {
const [job, setJob] = useState("");
const [jobList, setJobList] = useState(() => {
const storageJobList = JSON.parse(localStorage.getItem(JOB_KEY));
return storageJobList ?? [];
});
const handleAddJob = () => {
if (job === "") {
return;
}
setJobList((prevState) => {
const newJobList = [...prevState, job];
const jsonJobList = JSON.stringify(newJobList);
localStorage.setItem(JOB_KEY, jsonJobList);
return newJobList;
});
setJob("");
};
return (
setJob(e.target.value)} />
Add
{jobList.map((job, index) => (
{job}
))}
);
}
export default App;
Chức năng xóa: thêm 1 button trong thẻ li rồi gán hàm removejob bên dưới vào sự kiện onClick và truyền job vào là xong
//button trong thẻ li
{ removeJob(job) }}>Xóa
//hàm removeJob
var removeJob = function (job) {
setJobs((prev) => {
var newArray = prev.filter((item) => item !== job);
var jsonStringArray = JSON.stringify(newArray);
localStorage.setItem('TODO_APP', jsonStringArray);
return newArray;
})
}
them 1 the li nx dk a
fan cứng cmt đầu =)
chỗ setJobs(prev => [...prev, job]) thiếu điều kiện rồi, nếu mình không nhập gì vào thì ấn add sẽ hiện ra khoảng trắng.
Thầy Sơn đang lên từng bước thầy ấy sẽ làm sau khi làm xong video này, đó là
Bước 1: Quet Nha
Bước 2: Lau Nha
Bước 3: Giat Quan Ao
😂😂😂
có quét nhà mà chưa có lau nhà này -))) thầy cuteee
Hình như có sự nhầm lẫn thì phải. Ngay tại đoạn cuối của video, để tránh phải lập lại code bạn Sơn (xin lỗi chỗ này nhé, vì mình già lắm rồi, mình thích học thôi, nên gọi là bạn - mà đúng ra là thầy Sơn cũng được.) bạn Sơn có đem JSON.parse vào trong useState và dùng function ở chỗ này. Nếu đã có dữ liệu trong localStorage rồi thì nó ko bị gì. Còn nếu không có dữ liệu thì cái hàm đó nó return ra (null) và bị lỗi ngay. Chỗ này thì chỉ nên đem đoạn code sau vào useState. Câu lệnh nên viết như sau:
const [jobs, setJobs] = useState(JSON.parse(localStorage.getItem('jobs')) ?? [ ])
thì sẽ ko bị lỗi, vì khi gặp null nó sẽ chọn mảng rỗng. Xin cảm ơn rất nhiều
Phải truyền kiểu callback mới đúng a
const storageJobs = JSON.parse(localStorage.getItem("jobs")) return storageJobs ?? []. E thấy return vậy cg đúng ạ.
@@Misskieutra function App() {
const [job, setJob] = useState('');
const [jobs, setJobs] = useState(getStorage ?? []);
function getStorage() {
const storageJobs = JSON.parse(localStorage.getItem('jobs'));
return storageJobs;
}
Hay quá anh 2 =))
video đỉnh thật f8
Tuyệt vời!
Thanks anh!
E đã học qa nhìu hook nhưng cái useEffect hơi khó hiểu ở sau function phải có [ ]. Có khi còn phải thêm biến [variable]. Hóng a nói rõ về phần này khi ra video về useEffect ạ. E cảm ơn
Chào a buổi tối vui vẻ
Hay luôn anh ạ
dạo này bận việc học nên ít xem video của a
6:00 chưa dùng được jobs ngay sau khi setJobs
em nhận ra đoạn cuối cùng video có vấn đề. thay vì là return StorageJobs thì mình nên ghi là return StorageJobs === null ? [] : StorageJobs;
tại anh Sơn quên đó bạn, nhưng theo mình đúng hơn phải là return storageJobs ?? [ ] chứ như bạn còn thiếu trường hợp undefined
@@huonglexuan9697 bạn bị nhầm rồi. đang set mảng rỗng là giá trị khởi tạo mà . với Mình cũng hoàn thành khóa react bên udemy rồi ,qua f8 xem cho vui thôi
từ phút 13 trở đi tua lại 10 lần mới hiểu hết
Chúc mừng, bạn đã nắm được bí quyết học hành!
Mong khóa Node sắp tới của anh Sơn sẽ là NestJS ạ
ủa cái useState chỉ chạy 1 lần nhưng tại sao lúc in ra list job ấy sao lại lấy đc giá trị mới nhất của useState gán lại vào job trong khi nó lấy ở json vậy ạ
yêu nhà cái F8 nhiều :)))))
quá xịn
Mọi người cho mình hỏi sao 13:52 console.log(storageJobs) (line 16) chỉ ra 3 phần tử sau khi click Add vậy, đúng ra phải là 4 phần tử chứ (vì lúc này trong localStorage là 4 phần tử). Thanks all.
14:43 return storageJob ?? [ ]
Mọi người cho hỏi phút thứ 4:10 dòng 18
setJobs(prev => [...prev, job]);
khác gì với setJobs([...jobs, job])
Cám ơn Anh Sơn và các bạn
k có khác gì, chỉ là 1 cách viết khác thôi nha bạn...
Chỗ giá trị khởi tạo list sao lại dùng && mà ko dùng || v a
anh ơi anh có thể giải thích giúp em ở 2 dòng sử dụng useState khi mà mình thay đổi lại vị trí cho dòng đó thì thứ tự thực thi setState nó lại khác nhau không anh ?
Hôm nay mới học tới bài này, rất dễ hiểu và hữu ích, thanks a Sơn nhé, có bổ sung thêm là phần set useState job thì khi return cần thêm toán tử nullish storageJob ?? []
Cảm ơn em nha, lúc anh sửa lại xong quên mất chỗ đó 😢
anh ơi anh làm về ví dụ input upload image mà có tập hợp 3 cái input cho 3 cái ảnh
đi ạ
thiếu check null ở init state ở cuối video a ơi .
return storageJobList ?? [];
Cảm ơn bạn đã nhắc.
lúc storageJobs không có nó lấy [ ] thì f5 sẽ mất hết dữ liệu phải ko mn. vì useState chỉ chạy một lần 😐.
khi add nó chưa thêm luôn vào mang thi khi làm phần xóa không thể lấy index ra a ạ...mong a chỉ em cách làm ạ
14:00
return storageJobList ?? [];
hay
Ở cuối video đoạn return ra storageJobs vẫn phải thêm ?? [] chứ anh, không nó lại lỗi khi xóa JSON trong localstorage
Đúng rồi bạn ơi. Mình thiếu sót chỗ này
cuối video a truyền cái callback vào useState() mà đoạn return đó chưa check đc đoạn storageJobs = null thì lúc load trang mà chưa có 'jobs' trong storage thì ăn lỗi ròi 😢
Đúng rồi, anh thiết sót đó. Em sửa lại giúp anh nha
a sơn ơi, a cho e hỏi 1 vấn dề nhỏ, useState(initVAlue), vậy khi mỗi lần mình setState thì state này sẽ được lưu ở đâu v a
setState thì truyền về State
A Sơn cho e hỏi khi trong cùng 1 function a setJob(new value) va setJobs(new value) thi luc nay component se bi re-render lai 2 lan hay sao anh.Và sau khi kết thúc function đó nó mới set lai state, thi luc nay 2 cai state đó thay đổi nên nó re-render lại 2 lần hay chỉ 1 lần thôi ạ
Trong React < v18 thì setState nhiều lần (ko trong async/promise) thì chỉ re-render 1 lần, trong async/promise thì re-render ứng với số lần setState. React v18 thì cả 2 trường hợp đều setState 1 lần.
khi gắn value của input là job, thì nó warning, làm sao fix warning này vậy anh
"A component is changing an uncontrolled input to be controlled"
khai báo state mặc định lúc đầu là chuỗi nhé, nếu chỉ () thôi thì nó undefined -> lỗi ấy
12:10 em dùng toán tử || vẫn hoạt động được đúng không anh
Trường hợp này thì cũng tương tự nhau nha em. Dùng đc nha em.
Tại sao chỗ consle.log của e lại in ra 2 lần vậy ak
Ở index.js em xem có đang sùng comp StrictMode thì em comment nó lại nha
Cho em xin info cái ghê của anh được không ạ :))
anh ơi lúc handleSubmit thì mình nên kiểm tra xem có job ko rồi mới set lại để nó ko render ra li rỗng thì ok hơn ạ 😄
Ví dụ thôi mà em. Còn làm thật thì đâu chỉ có case em nói. Cảm ơn em nhé.
@@F8VNOfficial 😂vâng ,cảm ơn anh vì những khóa học tuyệt vời này ạ ❤❤
Làm sao để nâng cao tư duy viết code nhỉ. Đôi khi ko có ai hướng dẫn thì e mù luôn :v
Mình có câu hỏi: liệu có thể dùng setState(jobs.push(job)); có được không?
Ko bạn nhé. Quay trở lại bài học về method push() bạn sẽ biết nó trả về độ dài mới của mảng. Vd mảng có 3 phần tử rồi push thêm 1 phần từ length sẽ là 4. Như vậy setState sẽ lấy 4 làm state.
@@F8VNOfficial Mình cũng thắc mắc. Sao không gọi push() trực tiếp trong sự kiện click?
Thay vì định nghĩa lại hàm setJobs để cập nhật state cho jobs thì mình dùng push()/unshift() để cập nhật state thì sao ạ???
function TodoApp() {
const [jobs, setJobs] = useState([]);
const [input, setInput] = useState("");
function handleClick(e) {
jobs.unshift(input);
setInput("");
}
return (
React Todo App
setInput(e.target.value)} />
Add
{jobs.map((job, index) => (
{job}
))}
);
}
có ai làm update todolist không ạ cho miình xem code với
cmt nhì thôi :3
6:02 thực sự là chưa hiểu, ai giúp mình với 😞
xem kĩ lại video trước của a Sơn á bạn
Cho e hỏi mỗi khi change input thì sẽ component sẽ re-render 1 lần, có cách nào chỉ render 1 lần k a
render 1 lan thi lam sao no cap nhat duoc gia tri moi ban
a ơi cho e hỏi 'prev' là từ khóa hay sao anh?
ý e 'prev' là từ khóa hay biến ạ
Biến mình tự đặt tên thôi em nhé, trong video thì nó là tên tham số của hàm thôi em nhé
@@F8VNOfficial cảm ơn anh
giữa context api với redux thì mình nên chọn cái nào anh, hay học cả hai nhỉ
cả 2 luôn bạn ơi!!
@@nguyenanhkhoa149 thank ông nha
Khi mình không nhập dữ liệu mà mình nhấn vào Add thì nó vẫn render ra thẻ với giá trị rỗng a.
Mấy cái liên quan anh em tự xử lý thêm nhé. Vì mình đang học useState và todo chỉ lấy ra làm ví dụ thôi mà em
@@F8VNOfficial dạ a.
ngoài Quét nhà ra anh không biết làm gì nữa à :))
Biết code em 😂
hi idol
cho mình hỏi toán tử ?? tên là gì vậy? mình không nghe rõ :))
Là "nullish" nha bạn, sorry bạn mình phát âm thiếu "sh" ở cuối
@@F8VNOfficial cảm ơn Sơn nhé, mỗi video bài giảng của bạn thật sự rất chất lượng, rất dễ hiểu và hữu ích.
bt mình làm hơi máy móc, bạn nào có cách tối ưu không cho mình xin ý kiến =))
const handleDel = (index) => {
setJobs((prev) => {
prev = jobs.filter((job) => job !== jobs[index]);
const jsonJobs = JSON.stringify(prev);
localStorage.setItem("jobs", jsonJobs);
return prev;
});
};
const handleClearAll = () => {
setJobs((prev) => {
prev = jobs.splice(0, jobs.length);
const jsonJobs = JSON.stringify(prev);
localStorage.setItem("jobs", jsonJobs)
return prev;
});
};
return (
setJob(e.target.value)} />
Add
Clear All
{jobs.map((job, index) => (
{job}
handleDel(index)}>
X
))}
);
Mình có đoạn code này, bạn có thể tham khảo
const [job, setJob] = useState('')
const [jobs, setJobs] = useState(() => {
const storageJobs = JSON.parse(localStorage.getItem('jobs'))
return storageJobs ?? []
})
const saveLocalStorageJobs = (data) => {
const jobsJSON = JSON.stringify(data)
localStorage.setItem('jobs', jobsJSON)
}
const handleRemove = (indexValue) => {
setJobs(prev => {
const newJobs = prev.filter((item, index) => index !== indexValue)
saveLocalStorageJobs(newJobs)
return newJobs
})
}
const handleRemoveAll = () => {
setJobs(prev => {
const emptyArray = []
saveLocalStorageJobs(emptyArray )
return emptyArray
})
}
const handleClick = () => {
setJobs(prev => {
const stateJobs = [...prev, job]
//Save jobs to localStorage
saveLocalStorageJobs(stateJobs)
return stateJobs
})
setJob('')
}
return (
setJob(e.target.value)}
/>
Add
Remove All
{jobs.map((job, index) =>
{job}
handleRemove(index)}
>
Remove
)}
)
setJobs((prev) => {
prev = jobs.filter((job) => job !== jobs[index]);
const jsonJobs = JSON.stringify(prev);
localStorage.setItem("jobs", jsonJobs);
return prev;
});
};
đối với cái này b nên so sánh vs 2 id nha b so sánh như v sẽ xóa 2 phần tử nếu trùng tên đó vd bạn có 2 Task 1 khi b click sẽ xóa 2 cái Task 1
cho Delete:
const deleteList = ()=>{
localStorage.clear();
setJobs([])
}
Good job