const App = () => {
const [count, setCount] = useState(0);
return <h1 onClick={() => setCount(count + 1)}>{count}</h1>;
};const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
</>
);
}import { createContext, useContext } from "react";
const Context = createContext({ theme: "light" });
const Child = () => {
const { theme } = useContext(Context);
return <>{theme}</>;
};
const Parent = () => {
return <Child />;
};
const App = () => {
return (
<Context.Provider value={{ theme: "dark" }}>
<Parent />
</Context.Provider>
);
};
export default App;const App = () => {
useEffect(() => {
console.log(111);
}, []);
return <div>title</div>;
};const App = () => {
useLayoutEffect(() => {
console.log(111);
}, []);
return <div>title</div>;
};const App = () => {
useInsertionEffect(() => {
console.log(111);
}, []);
return <div>title</div>;
};import { useRef, forwardRef } from "react";
const Child = forwardRef((props: any, ref: any) => {
return <input ref={ref} />;
});
const Parent = () => {
const inputRef = (useRef < HTMLInputElement) | (null > null);
const onClick = () => {
if (inputRef.current) {
inputRef.current.value = "reset";
}
};
return (
<>
<Child ref={inputRef} />
<button onClick={onClick}>reset</button>
</>
);
};
const App = () => {
return <Parent />;
};
export default App;const App = () => {
const title = useMemo(() => "dao", []);
return <div>{title}</div>;
};const App = () => {
const setTitle = useCallback(() => {
console.log(111);
}, []);
return (
<button
type="button"
onClick={setTitle}
>
+
</button>
);
};const App = () => {
const [value, setValue] = useState("");
const [isPending, startTransition] = useTransition();
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
// 긴급처리건.
setValue(e.target.value);
startTransition(() => {
// 후순위 처리.
setContent(e.target.value);
});
};
return (
<>
<input
value={value}
onChange={onChange}
/>
<div>{value.length}</div>
</>
);
};const App = () => {
const [value, setValue] = useState("");
const lowValue = useDeferredValue(value.length);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
return (
<>
<input
value={value}
onChange={onChange}
/>
<div>{lowValue}</div>
</>
);
};// todoStore.js
let nextId = 0;
let todos = [{ id: nextId++, text: "Todo #1" }];
let listeners = [];
export const todosStore = {
addTodo() {
todos = [...todos, { id: nextId++, text: "Todo #" + nextId }];
emitChange();
},
subscribe(listener) {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter((l) => l !== listener);
};
},
getSnapshot() {
return todos;
},
};
function emitChange() {
for (let listener of listeners) {
listener();
}
}
// App.jsx
const App = () => {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
return (
<>
<button onClick={todosStore.addTodo}>Add todo</button>
<hr />
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</>
);
};// 여러번 불러오는 컴포넌트일 경우 아래와 같이 필요함.
const App = () => {
const inputId = useId();
return (
<>
<input id={`${inputId}-firstName`} />
<input id={`${inputId}-lastName`} />
</>
);
};
// ssr일경우 생성한 id가 다른경우가 있음.
// 1. 서버단 생성시 id="1" 생성
// 2. <div id="1"></div>을 client에게 전달
// 3. csr랭딩시 hydrate를 통해서 id="2" 로 처리.