初探 useEffect
render 完以後,瀏覽器 paint 之後你想要做什麼?
- 每一次 render 之後,都去執行 useEffect 內的 function
useEffect(() => {
console.log("alert render")
})
- 在某些 state 改變的時候,去執行 useEffect 內的 function
在 function 裡面加入第二個參數之後,當 todos 改變的時候,才去執行這個 useEffect
function writeTodoToLocalStorage(todos) {
window.localStorage.setItem("todos", JSON.stringify(todos));
}
useEffect(() => {
writeTodoToLocalStorage(todos)
}, [todos]);
// 加入第二個參數之後,當 todos 改變的時候,才去執行這個 useEffect
- 第二個參數,當裡面是空的時候(表示不會變),表示只有在第一次 render 完之後,才會執行這個 useEffect,第二次、第三次都不會
(注意:若是有初始值,在瀏覽器畫完畫面之後,才會去執行 useEffect,這樣會造成畫面會「閃一下」)
function writeTodoToLocalStorage(todos) {
window.localStorage.setItem("todos", JSON.stringify(todos));
}
useEffect(() => {
const todoData = window.localStorage.getItem('todos') || ""
if (todoDate) {
setTodos(JSON.parse(todoData));
}
}, []);
什麼是 useLayoutEffect
render 完之後,瀏覽器 paint 「之前」你想做什麼?
- 改善畫面會「閃一下」的狀況
useLayoutEffect(() => {
const todoData = window.localStorage.getItem('todos') || ""
if (todoDate) {
setTodos(JSON.parse(todoData));
}
}, []);
- React Hook Flow Diagram
- Run lazy initializers
在 useState 後面放 function(即是 lazy initializers)
function return 的東西會變成我們的初始值
const [todos, setTodos] = useState(() => {
console.log("init");
let todoData = window.localStorage.getItem("todos") || "";
if (todoData) {
todoData = JSON.parse(todoData);
id.current = todoData[0].id + 1;
} else {
todoData = []
}
})
再進一步了解 useEffect
- Cleanup LayoutEffect
在 useEffect 被清掉之前,想要做什麼事情?
useEffect(() => {
const todoData = window.localStorage.getItem('todos')
// clean up function
return () => {
}
}, [todos]);
第一次 render
第一次的 App()
todos: [{"id":1, "content":"123"}]
useEffect(() => {
const todoData = window.localStorage.getItem('todos')
return () => {
// clean up function
}
}, [todos]);
---
第二次 render,App()
todos: todos [{"id":1, "content":"123", "isDone":true}]
清掉 effect,再執行一次 useEffect
- Unmount
在 component 消失前,要做什麼事。
useEffect(() => {
return () => {
consoloe.log('unmount')
}
}, []);
寫一個自己的 hook!
抽出邏輯來共用,UI隨不同畫面而變化。
@ useInput.js
import { useState } from 'react';
export default function useInput() {
const [value, setValue] = useSate("");
const handleChange = e => {
setValue(e.targetValue)
}
return {
value,
setValue,
handleChange,
};
}
@ App.js
import unsInput from './useInput'
const { value, setValue, handleChange } = useInput()
const { todos, setTodos } = useTodos()
function App() {
return (
<input
type="text"
placeholder="todo"
value={value}
onChange={handleChange}
/>
)
}