useReducer
useReducer γ―γγͺγγ₯γΌγ΅ (reducer) γγ³γ³γγΌγγ³γγ«θΏ½ε γγγγοΏ½? React γγγ―γ§γγ
const [state, dispatch] = useReducer(reducer, initialArg, init?)- γͺγγ‘γ¬γ³γΉ
- δ½Ώη¨ζ³
- γγ©γγ«γ·γ₯γΌγγ£γ³γ°
- γ’γ―γ·γ§γ³γγγ£γΉγγγγγγγγ°γ«γ―ε€γ state οΏ½?ε€γ葨瀺γγγ
- γ’γ―γ·γ§γ³γγγ£γΉγγγγγγη»ι’γζ΄ζ°γγγͺγ
- γγ£γΉγγγεΎγ«γͺγγ₯γΌγ΅γγοΏ½? state οΏ½?δΈι¨γ undefined γ«γͺγ
- γγ£γΉγγγεΎγ«γͺγγ₯γΌγ΅γγοΏ½? state ε ¨δ½γ undefined γ«γͺγ
- βToo many re-rendersβ γ¨γγγ¨γ©γΌγηΊηγγ
- γͺγγ₯γΌγ΅γΎγγ―εζει’ζ°γ 2 εοΏ½?οΏ½θ‘γγγ
γͺγγ‘γ¬γ³γΉ
useReducer(reducer, initialArg, init?)
γͺγγ₯γΌγ΅ γ§ state γοΏ½?οΏ½ηγγγγγ«γγ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γ§ useReducer γεΌγ³εΊγγΎγγ
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...εΌζ°
reducer: state γγ©οΏ½?γγγ«ζ΄ζ°γγγγζοΏ½?οΏ½γγγͺγγ₯γΌγ΅ι’ζ°γ§γγη΄η²γ§γͺγγγ°γͺγγγεΌζ°γ¨γγ¦ state γ¨γ’γ―γ·γ§γ³γεγγ欑�? state γθΏγγΎγγstate γ¨γ’γ―γ·γ§γ³γ―γ©οΏ½?γγγͺεγ§γε€§δΈε€«γ§γγinitialArg: εζ state γθ¨οΏ½?οΏ½γγγε γ«γͺγε€γ§γγδ»»ζοΏ½?εοΏ½?ε€γζοΏ½?οΏ½γ§γγΎγγγ©οΏ½?γγγ«εζ state γθ¨οΏ½?οΏ½γγγγ―γ欑�?initεΌζ°γ«δΎεγγΎγγ- ηη₯ε―θ½
init: εζ state γθΏγεζει’ζ°γ§γγζοΏ½?οΏ½γγγ¦γγͺγε ΄εγεζ state γ―initialArgγοΏ½?γοΏ½?γ«γͺγγΎγγζοΏ½?οΏ½γγγ¦γγε ΄εγεζ state γ―init(initialArg)οΏ½?η΅ζγ«γͺγγΎγγ
θΏγε€
useReducer γ―γ2 γ€οΏ½?ε€γζγ€ι
εγθΏγγΎγοΌ
- ηΎε¨οΏ½? stateγζεοΏ½?γ¬γ³γγΌδΈγ«γ
init(initialArg)γΎγγ―initialArgοΌinitγγͺγε ΄εοΌγθ¨οΏ½?οΏ½γγγΎγγ - state γε₯οΏ½?ε€γ«ζ΄ζ°γγεγ¬γ³γγΌγγγͺγ¬γγγγοΏ½?
dispatchι’ζ°γ
注ζηΉ
useReducerγ―γγγ―γͺοΏ½?γ§γγ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γΎγγ―η¬θͺοΏ½?γ«γΉγΏγ γγγ―ε γ§οΏ½?γΏεΌγ³εΊγγγ¨γγ§γγΎγγγ«γΌγγζ‘δ»ΆοΏ½?δΈγ§εΌγ³εΊγγγ¨γ―γ§γγΎγγγεΏ θ¦γͺε ΄εγ―γζ°γγγ³γ³γγΌγγ³γγ¨γγ¦ζγεΊγγγοΏ½?δΈγ« state γη§»εγγγ¦γγ γγγ- Strict Mode γ§γ―γReact γ―η΄η²γ§γͺγι’ζ°γθ¦γ€γγγγγγγγγ«γγͺγγ₯γΌγ΅γ¨εζει’ζ°γ 2 εεΌγ³εΊγγΎγγγγγ―ιηΊζοΏ½?εδ½γ§γγγζ¬ηͺγ«γ―ε½±ιΏγγΎγγγγͺγγ₯γΌγ΅γ¨εζει’ζ°γη΄η²γ§γγγ°οΌγγγγγΉγγ§γοΌγγγγ―γγΈγγ―γ«ε½±ιΏγγΎγγγηζΉοΏ½?εΌγ³εΊγοΏ½?η΅ζγ―η‘θ¦γγγΎγγ
dispatch ι’ζ°
useReducer γ«γγ£γ¦θΏγγγ dispatch ι’ζ°γδ½Ώγγγ¨γ§γstate γε₯οΏ½?ε€γ«ζ΄ζ°γγ¦εγ¬γ³γγΌγγγͺγ¬γγγγ¨γγ§γγΎγγdispatch ι’ζ°γ«γ―γε―δΈοΏ½?εΌζ°γ¨γγ¦γ’γ―γ·γ§γ³γζΈ‘γεΏ
θ¦γγγγΎγγ
const [state, dispatch] = useReducer(reducer, { age: 42 });
function handleClick() {
dispatch({ type: 'incremented_age' });
// ...React γγ»γγγγ欑�? state γ―γεΌζ°γ¨γγ¦ state οΏ½?ηΎε¨ε€γγγ³ dispatch γ«ζΈ‘γγγγ’γ―γ·γ§γ³γη¨γγ¦ reducer ι’ζ°γεΌγ³εΊγγη΅ζγ«γͺγγΎγγ
εΌζ°
action: γ¦γΌγΆγ«γγ£γ¦οΏ½?οΏ½θ‘γγγγ’γ―γ·γ§γ³γ§γγδ»»ζοΏ½?εοΏ½?ε€γζοΏ½?οΏ½γ§γγΎγγζ £δΎγ¨γγ¦γγ’γ―γ·γ§γ³γ―ιεΈΈγͺγγΈγ§γ―γγ§γγγtypeγγγγγ£γ§θε₯γγγδ»οΏ½?γγγγγ£γ§γͺγγ·γ§γ³οΏ½?θΏ½ε ζ ε ±γδΏζγγΎγγ
θΏγε€
dispatch ι’ζ°γ«γ―θΏγε€γ―γγγΎγγγ
注ζηΉ
-
dispatchι’ζ°γ―γ欑�?γ¬γ³γγΌοΏ½?γγοΏ½? state ε€ζ°οΏ½?γΏγζ΄ζ°γγΎγγdispatchι’ζ°γεΌγ³εΊγγεΎγ« state ε€ζ°γθͺγΏεγγ¨γζ’γ«η»ι’δΈγ«θ‘¨η€Ίγγγ¦γγγdispatchεΌγ³εΊγεοΏ½?ε€γε€γθͺγΏεγγΎγγ -
δΈγγγγζ°γγε€γγ
Object.isοΏ½?ζ―θΌγ«γγγηΎε¨οΏ½?stateγ¨εγγ¨ε€ζγγγε ΄εγReact γ―γ³γ³γγΌγγ³γγ¨γοΏ½?εθ¦η΄ οΏ½?εγ¬γ³γγΌγγΉγγγγγΎγγγγγ―ζι©εγ§γγReact γ―η΅ζγη‘θ¦γ§γγε ΄εγ§γεΏ θ¦γγγ£γ¦γ³γ³γγΌγγ³γγεΌγ³εΊγγγγγγΎγγγγγγγγ³γΌγγ«ε½±ιΏγγ¦γ―γγγΎγγγ -
React γ― state οΏ½?ζ΄ζ°οΏ½?γγγε¦ηοΌbatching, ζγε¦ηοΌ γθ‘γγΎγγγγγ«γγγγγΉγ¦οΏ½?γ€γγ³γγγ³γγ©γοΏ½?οΏ½θ‘γγγγγγοΏ½?
setι’ζ°γεΌγ³εΊγγγεΎγ«η»ι’γζ΄ζ°γγγΎγγγγγ«γγγ1 γ€οΏ½?γ€γγ³γδΈγ«θ€ζ°εοΏ½?εγ¬γ³γγΌγηΊηγγοΏ½?γι²γγγ¨γγ§γγΎγγη¨γͺγ±γΌγΉγ¨γγ¦γDOM γ«γ’γ―γ»γΉγγγͺγ©οΏ½?ηη±γ§ React γ«η»ι’γζ©ζγ«εΌ·εΆηγ«ζ΄ζ°γγγεΏ θ¦γγγε ΄εγ―γflushSyncγδ½Ώη¨γ§γγΎγγ
δ½Ώη¨ζ³
γ³γ³γγΌγγ³γγ«γͺγγ₯γΌγ΅γθΏ½ε γγ
γ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γ§ useReducer γεΌγ³εΊγγ¦γγͺγγ₯γΌγ΅γδ½Ώγ£γ¦ state γοΏ½?οΏ½ηγγΎγγ
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...useReducer γ―γ2 γ€οΏ½?ε€γζγ€ι
εγθΏγγΎγοΌ
- γοΏ½? state ε€ζ°οΏ½?ηΎε¨οΏ½? stateγδΈγγγγεζ state γεζε€γ¨γγ¦θ¨οΏ½?οΏ½γγγΎγγ
- γ¦γΌγΆζδ½γ«εΏγγ¦ state γε€ζ΄γγγγοΏ½?
dispatchι’ζ°γ
η»ι’δΈοΏ½?ε
οΏ½?οΏ½γζ΄ζ°γγγ«γ―γγ’γ―γ·γ§γ³γ¨εΌγ°γγγγ¦γΌγΆγθ‘γ£γγγ¨γ葨γγͺγγΈγ§γ―γγεΌζ°γ¨γγ¦ dispatch γεΌγ³εΊγγΎγγ
function handleClick() {
dispatch({ type: 'incremented_age' });
}React γ―ηΎε¨οΏ½? state γ¨γ’γ―γ·γ§γ³γγͺγγ₯γΌγ΅ι’ζ°γ«ζΈ‘γγΎγγγͺγγ₯γΌγ΅γ―欑�? state γθ¨οΏ½?οΏ½γγ¦θΏγγΎγγReact γ―γοΏ½?欑�? state γδΏεγγγ¨γ¨γγ«γγοΏ½? state γδ½Ώγ£γ¦γ³γ³γγΌγγ³γγγ¬γ³γγΌγγUI γζ΄ζ°γγΎγγ
import { useReducer } from 'react'; function reducer(state, action) { if (action.type === 'incremented_age') { return { age: state.age + 1 }; } throw Error('Unknown action.'); } export default function Counter() { const [state, dispatch] = useReducer(reducer, { age: 42 }); return ( <> <button onClick={() => { dispatch({ type: 'incremented_age' }) }}> Increment age </button> <p>Hello! You are {state.age}.</p> </> ); }
useReducer γ― useState γ¨ιεΈΈγ«δΌΌγ¦γγΎγγγγ€γγ³γγγ³γγ©γγ state ζ΄ζ°γγΈγγ―γγ³γ³γγΌγγ³γοΏ½?ε€οΏ½?εδΈοΏ½?ι’ζ°γ«η§»εγγγγ¨γγ§γγΎγγθ©³γγγ―γuseState γ¨ useReducer οΏ½?ιΈγ³ζΉγεη
§γγ γγγ
γͺγγ₯γΌγ΅ι’ζ°οΏ½?ζΈγζΉ
γͺγγ₯γΌγ΅ι’ζ°γ―欑�?γγγ«οΏ½?οΏ½θ¨γγγΎγοΌ
function reducer(state, action) {
// ...
}γοΏ½?εΎγ欑�? state γθ¨οΏ½?οΏ½γγ¦θΏγγ³γΌγγδΈγ«ζΈγγ¦γγγΎγγζ
£δΎγ¨γγ¦γswitch ζγ¨γγ¦ζΈγγγ¨γδΈθ¬ηγ§γγswitch οΏ½?ε case γγ¨γ«γ欑�? state γθ¨οΏ½?οΏ½γγ¦θΏγγΎγγ
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
return {
name: state.name,
age: state.age + 1
};
}
case 'changed_name': {
return {
name: action.nextName,
age: state.age
};
}
}
throw Error('Unknown action: ' + action.type);
}γ’γ―γ·γ§γ³οΏ½?ε½’γ―γ©οΏ½?γγγͺγοΏ½?γ§γζ§γγΎγγγζ
£δΎγ¨γγ¦γγ’γ―γ·γ§γ³γθε₯γγγγοΏ½? type γγγγγ£γζγ£γγͺγγΈγ§γ―γγζΈ‘γγγ¨γδΈθ¬ηγ§γγγ’γ―γ·γ§γ³γ«γ―γͺγγ₯γΌγ΅γ欑�? state γθ¨οΏ½?οΏ½γγγγγ«εΏ
θ¦γͺζε°ιοΏ½?ζ
ε ±γε«γγγΉγγ§γγ
function Form() {
const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 });
function handleButtonClick() {
dispatch({ type: 'incremented_age' });
}
function handleInputChange(e) {
dispatch({
type: 'changed_name',
nextName: e.target.value
});
}
// ...γ’γ―γ·γ§γ³οΏ½?γΏγ€γεγ―γ³γ³γγΌγγ³γε γ«γγΌγ«γ«γͺγοΏ½?γ§γγεγ’γ―γ·γ§γ³γ―γθ€ζ°οΏ½?γγΌγΏοΏ½?ε€ζ΄γ«γ€γͺγγγοΏ½?γ§γγ£γ¦γγεδΈοΏ½?γ¦γΌγΆζδ½γ葨γγγγ«γγ¦γγ γγγstate οΏ½?ε½’γ―δ»»ζγ§γγγιεΈΈγ―γͺγγΈγ§γ―γγΎγγ―ι εγ«γͺγγΎγγ
θ©³γγγ―γγͺγγ₯γΌγ΅γΈοΏ½? state γγΈγγ―οΏ½?ζ½εΊγεη §γγ γγγ
δΎ 1/3: γγ©γΌγ οΌγͺγγΈγ§γ―γοΌ
γοΏ½?δΎγ§γ―γγͺγγ₯γΌγ΅γ 2 γ€οΏ½?γγ£γΌγ«γοΌname γ¨ ageοΌγζγ€ state γͺγγΈγ§γ―γγοΏ½?οΏ½ηγγ¦γγΎγγ
import { useReducer } from 'react'; function reducer(state, action) { switch (action.type) { case 'incremented_age': { return { name: state.name, age: state.age + 1 }; } case 'changed_name': { return { name: action.nextName, age: state.age }; } } throw Error('Unknown action: ' + action.type); } const initialState = { name: 'Taylor', age: 42 }; export default function Form() { const [state, dispatch] = useReducer(reducer, initialState); function handleButtonClick() { dispatch({ type: 'incremented_age' }); } function handleInputChange(e) { dispatch({ type: 'changed_name', nextName: e.target.value }); } return ( <> <input value={state.name} onChange={handleInputChange} /> <button onClick={handleButtonClick}> Increment age </button> <p>Hello, {state.name}. You are {state.age}.</p> </> ); }
εζ state οΏ½?εδ½ζγιΏγγ
React γ―εζ state γδΈεΊ¦δΏεγγοΏ½?γ‘γ欑εδ»₯ιοΏ½?γ¬γ³γγΌγ§γ―η‘θ¦γγΎγγ
function createInitialState(username) {
// ...
}
function TodoList({ username }) {
const [state, dispatch] = useReducer(reducer, createInitialState(username));
// ...createInitialState(username) οΏ½?η΅ζγ―εζγ¬γ³γγΌγ§οΏ½?γΏδ½Ώη¨γγγΎγγγγ¬γ³γγΌοΏ½?εΊ¦γ«ζ―εγοΏ½?ι’ζ°γεΌγ³εΊγγ¦γγΎγγγγγ―γε€§γγͺι
εγδ½ζγγγγι«γ³γΉγγͺθ¨οΏ½?οΏ½γθ‘γ£γγγγ¦γγε ΄εγ«η‘ι§γ«γͺγε―θ½ζ§γγγγΎγγ
γγγθ§£ζ±Ίγγγγγ«γuseReducer οΏ½? 3 ηͺοΏ½?οΏ½?εΌζ°γ¨γγ¦εζει’ζ°γζΈ‘γγγ¨γγ§γγΎγοΌ
function createInitialState(username) {
// ...
}
function TodoList({ username }) {
const [state, dispatch] = useReducer(reducer, username, createInitialState);
// ...createInitialState γζΈ‘γγ¦γγγγ¨γ«ζ³¨ζγγ¦γγ γγγγγγ―ι’ζ°γοΏ½?γοΏ½?γ§γγγcreateInitialState() γ§γ―γγγΎγγγγγγ«γγγεζ state γ―εζεεΎγ«εδ½ζγγγͺγγͺγγΎγγ
δΈθ¨οΏ½?δΎγ§γ―γcreateInitialState γ― username εΌζ°γεγεγγΎγγεζει’ζ°γεζ state γθ¨οΏ½?οΏ½γγγγγ«ζ
ε ±γεΏ
θ¦γ¨γγͺγε ΄εγ―γuseReducer γ«ε―Ύγγ¦ 2 ηͺοΏ½?οΏ½?εΌζ°γ¨γγ¦ null γζΈ‘γγγ¨γγ§γγΎγγ
δΎ 1/2: εζει’ζ°γζΈ‘γ
γοΏ½?δΎγ§γ―γεζει’ζ°γζΈ‘γγ¦γγγγγcreateInitialState ι’ζ°γ―εζεζγ«οΏ½?γΏοΏ½?οΏ½θ‘γγγΎγγεζει’ζ°γ―ε
₯εγγ£γΌγ«γγ«ζεγε
₯εγγγͺγ©γ§γ³γ³γγΌγγ³γγεγ¬γ³γγΌγγγγ¨γγ¦γοΏ½?οΏ½θ‘γγγΎγγγ
import { useReducer } from 'react'; function createInitialState(username) { const initialTodos = []; for (let i = 0; i < 50; i++) { initialTodos.push({ id: i, text: username + "'s task #" + (i + 1) }); } return { draft: '', todos: initialTodos, }; } function reducer(state, action) { switch (action.type) { case 'changed_draft': { return { draft: action.nextDraft, todos: state.todos, }; }; case 'added_todo': { return { draft: '', todos: [{ id: state.todos.length, text: state.draft }, ...state.todos] } } } throw Error('Unknown action: ' + action.type); } export default function TodoList({ username }) { const [state, dispatch] = useReducer( reducer, username, createInitialState ); return ( <> <input value={state.draft} onChange={e => { dispatch({ type: 'changed_draft', nextDraft: e.target.value }) }} /> <button onClick={() => { dispatch({ type: 'added_todo' }); }}>Add</button> <ul> {state.todos.map(item => ( <li key={item.id}> {item.text} </li> ))} </ul> </> ); }
γγ©γγ«γ·γ₯γΌγγ£γ³γ°
γ’γ―γ·γ§γ³γγγ£γΉγγγγγγγγ°γ«γ―ε€γ state οΏ½?ε€γ葨瀺γγγ
dispatch ι’ζ°γεΌγ³εΊγγ¦γγοΏ½?οΏ½θ‘δΈοΏ½?γ³γΌγε
οΏ½? state γ―ε€ζ΄γγγΎγγοΌ
function handleClick() {
console.log(state.age); // 42
dispatch({ type: 'incremented_age' }); // Request a re-render with 43
console.log(state.age); // Still 42!
setTimeout(() => {
console.log(state.age); // Also 42!
}, 5000);
}γγγ― state γγΉγγγγ·γ§γγοΏ½?γγγ«ζ―γθγγγγ§γγstate γζ΄ζ°γγγ¨γζ°γγ state οΏ½?ε€γ§εγ¬γ³γγΌγθ¦ζ±γγγΎγγγζ’γ«οΏ½?οΏ½θ‘δΈοΏ½?γ€γγ³γγγ³γγ©ε
οΏ½? state JavaScript ε€ζ°γ«γ―ε½±ιΏγδΈγγΎγγγ
欑�? state οΏ½?ε€γζ¨ζΈ¬γγεΏ θ¦γγγε ΄εγ―γγͺγγ₯γΌγ΅γθͺεγ§εΌγ³εΊγγγ¨γ§ζεγ§θ¨οΏ½?οΏ½γγγγ¨γγ§γγΎγοΌ
const action = { type: 'incremented_age' };
dispatch(action);
const nextState = reducer(state, action);
console.log(state); // { age: 42 }
console.log(nextState); // { age: 43 }γ’γ―γ·γ§γ³γγγ£γΉγγγγγγη»ι’γζ΄ζ°γγγͺγ
React γ―γObject.is οΏ½?ζ―θΌγ«γγγ欑�? state γεοΏ½? state γ¨ηγγγ¨ε€ζγγγε ΄εγζ΄ζ°γη‘θ¦γγΎγγγγγ―ιεΈΈγstate ε
οΏ½?γͺγγΈγ§γ―γγι
εγη΄ζ₯ζΈγζγγε ΄εγ«ηΊηγγΎγοΌ
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// π© Wrong: mutating existing object
state.age++;
return state;
}
case 'changed_name': {
// π© Wrong: mutating existing object
state.name = action.nextName;
return state;
}
// ...
}
}ζ’εοΏ½? state γͺγγΈγ§γ―γγζΈγζγγ¦θΏγγ¦γγγγγReact γ―ζ΄ζ°γη‘θ¦γγΎγγγγγοΏ½?ζ£γγγ«γ―γεΈΈγ« state ε
οΏ½?γͺγγΈγ§γ―γοΏ½?ζ΄ζ°γ state ε
οΏ½?ι
εοΏ½?ζ΄ζ°γζ£γγθ‘γγγγγοΏ½?ζΈγζγγιΏγγεΏ
θ¦γγγγΎγγ
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// β
Correct: creating a new object
return {
...state,
age: state.age + 1
};
}
case 'changed_name': {
// β
Correct: creating a new object
return {
...state,
name: action.nextName
};
}
// ...
}
}γγ£γΉγγγεΎγ«γͺγγ₯γΌγ΅γγοΏ½? state οΏ½?δΈι¨γ undefined γ«γͺγ
ζ°γγ state γθΏγιγ«γγγΉγ¦οΏ½? case οΏ½?εε²γ«γγγ¦γγΉγ¦οΏ½?ζ’εοΏ½?γγ£γΌγ«γγγ³γγΌγγγγγ«γͺγ£γ¦γγγη’Ίθͺγγ¦γγ γγοΌ
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
return {
...state, // Don't forget this!
age: state.age + 1
};
}
// ...δΈθ¨οΏ½? ...state γηη₯γγγ¨γθΏγγγ欑�? state γ«γ― age γγ£γΌγ«γοΏ½?γΏγε«γΎγγδ»οΏ½?γγ£γΌγ«γγ―δ½γε«γΎγγͺγγͺγ£γ¦γγΎγγΎγγ
γγ£γΉγγγεΎγ«γͺγγ₯γΌγ΅γγοΏ½? state ε ¨δ½γ undefined γ«γͺγ
state γδΊζγγ undefined γ«γͺγε ΄εγγγγγγγγγοΏ½? case γ§ state γ return γεΏγγ¦γγγγγ’γ―γ·γ§γ³οΏ½?γΏγ€γγγγγοΏ½? case γ¨γδΈθ΄γγ¦γγͺγγγγ§γγεε γθ¦γ€γγγγγ«γswitch οΏ½?ε€γ§γ¨γ©γΌγγΉγγΌγγ¦γΏγΎγγγγ
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// ...
}
case 'edited_name': {
// ...
}
}
throw Error('Unknown action: ' + action.type);
}γΎγγγοΏ½?γγγͺγγΉγγγ£γγγγγγγ«γTypeScript οΏ½?γγγͺιηεγγ§γγ«γδ½Ώη¨γγγγ¨γγ§γγΎγγ
βToo many re-rendersβ γ¨γγγ¨γ©γΌγηΊηγγ
Too many re-renders. React limits the number of renders to prevent an infinite loop. γ¨γγγ¨γ©γΌγ葨瀺γγγγγ¨γγγγΎγγιεΈΈγγγγ―γ¬γ³γγΌδΈγ«γ’γ―γ·γ§γ³γη‘ζ‘δ»Άγ§γγ£γΉγγγγγ¦γγγγγγ³γ³γγΌγγ³γγγ«γΌγγ«ε
₯γ£γ¦γγγγ¨γζε³γγΎγοΌγ¬γ³γγΌγγγ£γΉγγγοΌγγγ«γγεεΊ¦γ¬γ³γγΌγηΊηοΌγγ¬γ³γγΌγγγ£γΉγγγοΌγγγ«γγεεΊ¦γ¬γ³γγΌγηΊηοΌγγ¨γγ£γηΉ°γθΏγγ§γγιεΈΈγ«ε€γοΏ½?ε ΄εγγγγ―γ€γγ³γγγ³γγ©οΏ½?ζοΏ½?οΏ½ζΉζ³οΏ½?γγΉγ«γγ£γ¦εΌγθ΅·γγγγΎγγ
// π© Wrong: calls the handler during render
return <button onClick={handleClick()}>Click me</button>
// β
Correct: passes down the event handler
return <button onClick={handleClick}>Click me</button>
// β
Correct: passes down an inline function
return <button onClick={(e) => handleClick(e)}>Click me</button>γοΏ½?γ¨γ©γΌοΏ½?εε γγγγγͺγε ΄εγ―γγ³γ³γ½γΌγ«οΏ½?γ¨γ©γΌοΏ½?ζ¨ͺγ«γγη’ε°γγ―γͺγγ―γγJavaScript γΉγΏγγ―γθͺΏγΉγ¦γ¨γ©γΌοΏ½?εε γ¨γͺγε
·δ½ηγͺ dispatch ι’ζ°εΌγ³εΊγγθ¦γ€γγ¦γγ γγγ
γͺγγ₯γΌγ΅γΎγγ―εζει’ζ°γ 2 εοΏ½?οΏ½θ‘γγγ
Strict Mode γ§γ―γReact γ―γͺγγ₯γΌγ΅γ¨εζει’ζ°γ 2 εεΌγ³εΊγγΎγγγγγ«γγ£γ¦γ³γΌγγε£γγγγ¨γγγ£γ¦γ―γͺγγΎγγγ
γοΏ½?ιηΊε°η¨οΏ½?ζ―γθγγ―γγ³γ³γγΌγγ³γγη΄η²γ«δΏγ€γγγ«ε½Ήη«γ‘γΎγγReact γ― 2 εοΏ½?εΌγ³εΊγοΏ½?γγ‘οΏ½? 1 γ€οΏ½?η΅ζγδ½Ώη¨γγγγ 1 γ€οΏ½?η΅ζγ―η‘θ¦γγΎγγγ³γ³γγΌγγ³γγγ€γγ·γ£γ©γ€γΆγγγγ³γͺγγ₯γΌγ΅ι’ζ°γη΄η²γ§γγιγγγγγ―γγΈγγ―γ«ε½±ιΏγδΈγγΎγγγγγ γγγγγοΏ½?ι’ζ°γθͺ€γ£γ¦γγ¦δΈη΄γ§γγε ΄εγγγγ«γγγγΉγ«ζ°δ»γγγ¨γγ§γγΎγγ
δΎγγ°γδ»₯δΈοΏ½?η΄η²γ§γͺγγͺγγ₯γΌγ΅ι’ζ°γ―γΉγγΌγε οΏ½?ι εγζΈγζγγ¦γγΎγοΌ
function reducer(state, action) {
switch (action.type) {
case 'added_todo': {
// π© Mistake: mutating state
state.todos.push({ id: nextId++, text: action.text });
return state;
}
// ...
}
}React γγͺγγ₯γΌγ΅ι’ζ°γ 2 εεΌγ³εΊγγγγtodo γ 2 εθΏ½ε γγγγγ¨γγγγγγγΉγγγγγ¨γγγγγΎγγγοΏ½?δΎγ§γ―γι εοΏ½?ζΈγζγγ§γ―γͺγοΏ½?γζγγθ‘γγγ¨γ§γγΉγοΏ½?ζ£γ§γγΎγοΌ
function reducer(state, action) {
switch (action.type) {
case 'added_todo': {
// β
Correct: replacing with new state
return {
...state,
todos: [
...state.todos,
{ id: nextId++, text: action.text }
]
};
}
// ...
}
}γγγ§γͺγγ₯γΌγ΅ι’ζ°γ―η΄η²γ«γͺγ£γγγγ1 εδ½εγ«εΌγ³εΊγγγ¦γεδ½γ«ε½±ιΏγ―γγγΎγγγγγγ React γ 2 εεΌγ³εΊγγγ¨γ§γγΉγηΊθ¦γ§γγηη±γ§γγγ³γ³γγΌγγ³γγεζει’ζ°γγγγ³γͺγγ₯γΌγ΅ι’ζ°οΏ½?γΏγη΄η²γ§γγεΏ θ¦γγγγΎγγγ€γγ³γγγ³γγ©γ―η΄η²γ§γγεΏ θ¦γ―γͺγγγγReact γ―γ€γγ³γγγ³γγ©γ 2 εεΌγ³εΊγγγ¨γ―γγγΎγγγ
θ©³η΄°γ―γγ³γ³γγΌγγ³γγη΄η²γ«δΏγ€γεη §γγ¦γγ γγγ