diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.eslintrc.cjs" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.eslintrc.cjs"
new file mode 100644
index 0000000..3e212e1
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.eslintrc.cjs"
@@ -0,0 +1,21 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:react/jsx-runtime',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
+ settings: { react: { version: '18.2' } },
+ plugins: ['react-refresh'],
+ rules: {
+ 'react/jsx-no-target-blank': 'off',
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.gitignore" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.gitignore"
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/.gitignore"
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/README.md" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/README.md"
new file mode 100644
index 0000000..f768e33
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/README.md"
@@ -0,0 +1,8 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/index.html" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/index.html"
new file mode 100644
index 0000000..0c589ec
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/index.html"
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React
+
+
+
+
+
+
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/package.json" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/package.json"
new file mode 100644
index 0000000..60e6908
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/package.json"
@@ -0,0 +1,24 @@
+{
+ "name": "react-19-example",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^19.0.0-canary-fd0da3eef-20240404",
+ "react-dom": "^19.0.0-canary-fd0da3eef-20240404"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.2.1",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react": "^7.34.1",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.6",
+ "vite": "^5.2.0"
+ }
+}
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/App.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/App.jsx"
new file mode 100644
index 0000000..9cdf27e
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/App.jsx"
@@ -0,0 +1,25 @@
+import UseStatusForm from "./components/UseStatusForm";
+import UseStateForm from "./components/UseStateForm";
+import Optimistic from "./components/Optimistic/Optimistic";
+
+function App() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/Optimistic.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/Optimistic.jsx"
new file mode 100644
index 0000000..a31f8eb
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/Optimistic.jsx"
@@ -0,0 +1,48 @@
+import { useOptimistic, useState } from "react";
+
+const DEFAULT_MESSAGES = [{ text: "Hey, I am initail", sending: false, key: 1 }];
+
+const Optimistic = () => {
+ const [messages, setMessages] = useState(DEFAULT_MESSAGES);
+ const [optimisticMessages, addOptimisticMessage] = useOptimistic(messages, (state, newMessage) => [
+ ...state,
+ { text: newMessage, sending: true },
+ ]);
+
+ async function handleSendFormData(formData) {
+ const sentMessage = await fakeDelayAction(formData.get("message"));
+ setMessages((messages) => [...messages, { text: sentMessage }]);
+ }
+
+ const handleSubmit = async (userData) => {
+ addOptimisticMessage(userData.get("username"));
+
+ await handleSendFormData(userData);
+ };
+
+ return (
+ <>
+ {optimisticMessages.map((message, index) => (
+
+ {message.text}
+ {!!message.sending && (Sending...)}
+
+ ))}
+
+ >
+ );
+};
+
+export default Optimistic;
+
+async function fakeDelayAction(message) {
+ await new Promise((res) => setTimeout(res, 3000));
+ return message;
+}
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/index.js" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/index.js"
new file mode 100644
index 0000000..d2b81f6
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/Optimistic/index.js"
@@ -0,0 +1 @@
+export { default } from "./Optimistic";
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/UseStateForm.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/UseStateForm.jsx"
new file mode 100644
index 0000000..0fb2830
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/UseStateForm.jsx"
@@ -0,0 +1,26 @@
+import { useFormState } from "react-dom";
+
+const UseStateForm = () => {
+ const [message, formAction] = useFormState(handleSubmit, null);
+
+ return (
+
+ );
+};
+
+const handleSubmit = (prevState, queryData) => {
+ const name = queryData.get("username");
+ console.log(prevState);
+
+ if (name === "Chanyeong") {
+ return { success: true, text: "Welcome" };
+ }
+ return { success: false, text: "Error" };
+};
+
+export default UseStateForm;
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/index.js" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/index.js"
new file mode 100644
index 0000000..0a75218
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStateForm/index.js"
@@ -0,0 +1 @@
+export { default } from "./UseStateForm";
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/Submit.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/Submit.jsx"
new file mode 100644
index 0000000..1d7711b
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/Submit.jsx"
@@ -0,0 +1,9 @@
+import { useFormStatus } from "react-dom";
+
+const Submit = () => {
+ const { pending } = useFormStatus();
+
+ return ;
+};
+
+export default Submit;
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/UseStatusForm.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/UseStatusForm.jsx"
new file mode 100644
index 0000000..bc871e3
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/UseStatusForm.jsx"
@@ -0,0 +1,13 @@
+import Submit from "./Submit";
+
+const UseStatusForm = () => {
+ return (
+
+ );
+};
+
+const handleSubmit = () => new Promise((res) => setTimeout(res, 3000));
+
+export default UseStatusForm;
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/index.js" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/index.js"
new file mode 100644
index 0000000..922e1e3
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/components/UseStatusForm/index.js"
@@ -0,0 +1 @@
+export { default } from "./UseStatusForm";
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/main.jsx" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/main.jsx"
new file mode 100644
index 0000000..0d1758a
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/src/main.jsx"
@@ -0,0 +1,9 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+
+ReactDOM.createRoot(document.getElementById("root")).render(
+
+
+
+);
diff --git "a/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/vite.config.js" "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/vite.config.js"
new file mode 100644
index 0000000..5a33944
--- /dev/null
+++ "b/99. \355\220\201\353\213\271\355\220\201\353\213\271/7\355\232\214\354\260\250/\354\260\254\354\230\201/react-19-example/vite.config.js"
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
diff --git a/React19.md b/React19.md
new file mode 100644
index 0000000..9277574
--- /dev/null
+++ b/React19.md
@@ -0,0 +1,49 @@
+# react 19 정리
+
+## 주 변화
+
+### concurrent rendering
+
+- react18이 synchronous rendering에 의존했던것과 달리, react19는 동시성을 활용해, UI 업데이트를 더 작은 비동기 작업으로 세분화함
+- 우선순위가 높은 업데이트를 먼저 처리해 더 매끄럽고 유연한 사용자 경험을 제공함
+
+### suspense for data fetching reinvented
+
+- 데이터를 불러올때 사용하는 suspense에 대한 성능 개선
+- suspense가 concurrent rendering과 원활하게 통합되기 때문에 최적의 성능을 위해 데이터를 가져오는 작업과 렌더링을 동시에 진행할 수도 있음
+
+### server side rendering 개선
+
+- streaming과 concurrent가 발전했다는 점을 활용해 더 빠른 TTFB와 향상된 SEO 성능을 제공함
+
+> TTFB: Time to First Byte로 브라우저가 페이지를 요청한 시점과 서버로부터 첫 번째 정보 byte를 수신한 시점 사이의 시간
+
+### 점진적 도입 가능
+
+- 기존 react 생태계가 다양하다는 사실을 인지하고, 개발자가 react 프로젝트를 점진적으로 upgrade할 수 있음
+
+### performance optimization
+
+- react19는 runtime 효율은 높이고 번들 사이즈는 줄이기 위해 다양한 성능 최적화 기술을 사용함
+- 최적화된 조정 알고리즘부터 지연 컴포넌트 로딩에 이르기까지, 더 빠른 렌더링과 효율적인 메모리 관리 기능을 제공하기 위해 노력
+- 새로운 scheduler architecture를 도입해, 렌더링 우선순위와 resource활용도를 세밀하게 제어하고 성능 튜닝을 강화할 수 있도록 도움
+
+### debugging developer tool
+
+- react19를 사용하는 개발자는 component life cycle, state management, performance bottleneck 등에 대한 상세한 insight를 확보하고, 앱을 보다 효과적으로 최적화 할 수 있음
+- time-slicing profiler와 flame charts와 같은 기능을 통해 이전보다 향상된 정밀도로 성능 관련 문제를 진단하고 해결하도록 지원
+
+#### time-slicing profiler
+
+#### flame chart
+
+### 핵심 기능
+
+#### react compiler (experimental)
+
+- react를 더 작고 최적화된 javascript로 compile함으로써, TTFB 및 UX 개선할 수 있음
+- 아직 experimental 단계로, 널리 사용할 준비는 되어있지 않음
+
+#### reference
+
+- https://kmong.com/article/1852--React-19-%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EB%8A%A5-%ED%95%9C%EB%88%88%EC%97%90-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0