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é 😍😍
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; }) }
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
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
@@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
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 ?? []
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 ?
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.
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.
ủ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 ạ
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 😢
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 (
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
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
Đã 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
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.
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;
}
từ phút 13 trở đi tua lại 10 lần mới hiểu hết
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
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
fan cứng cmt đầu =)
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
Hay quá anh 2 =))
Tuyệt vời!
Thanks anh!
Hay luôn anh ạ
dạo này bận việc học nên ít xem video của a
Mong khóa Node sắp tới của anh Sơn sẽ là NestJS ạ
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 ạ
Chào a buổi tối vui vẻ
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 ạ
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ỗ đó 😢
video đỉnh thật f8
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
quá xịn
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 ?
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.
thiếu check null ở init state ở cuối video a ơi .
return storageJobList ?? [];
Cảm ơn bạn đã nhắc.
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 ạ ❤❤
Cho em xin info cái ghê của anh được không ạ :))
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...
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.
14:43 return storageJob ?? [ ]
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
ủ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 ạ
Chỗ giá trị khởi tạo list sao lại dùng && mà ko dùng || v a
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
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 😐.
6:00 chưa dùng được jobs ngay sau khi setJobs
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
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}
))}
);
}
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
có ai làm update todolist không ạ cho miình xem code với
yêu nhà cái F8 nhiều :)))))
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
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.
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
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
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
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
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.
14:00
return storageJobList ?? [];
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
ngoài Quét nhà ra anh không biết làm gì nữa à :))
Biết code em 😂
cmt nhì thôi :3
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.
cho Delete:
const deleteList = ()=>{
localStorage.clear();
setJobs([])
}
Good job