화면에 바인딩(렌더링)되는 데이타
- props
- state, 값이 변할 수 있다.
proactive, 선제적 <-> reactive, 즉각적으로
컴포넌트 라이프 사이클
1. 메모리 적재
2. 화면에 렌더링
3. 리렌더링
4. 메모리 해제
useEffect() Hook
-> componetWillMount
-> componetDidMount
-> componetWillUnmount
==============================>
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/todos')
.then((res)=>{
setTodos(res.data);
});
}, []);
if (!todos) return <h1>데이터 없음</h1>
return (
<>
<h1>{todos[0].title}</h1>
</>
);
}
export default App;
==============================>
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/todos')
.then((res)=>{
setTodos(res.data);
});
}, []);
if (!todos) return <h1>데이터 없음</h1>
return (
<>
<h1>todo list</h1>
<ul>
{todos.map(todo =>
<li>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
promise code
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
const fetchTodosFromFakeServer = () => {
.then((res)=>{
console.log(res.data);
setTodos(res.data);
})
.catch((error) => {
console.log(error);
});
};
useEffect(() => {
fetchTodosFromFakeServer()
},[]);
if (!todos) {
return <h1>데이터 없음</h1>;
}
return (
<>
<h1>todo list</h1>
<button onClick={fetchTodosFromFakeServer}>다시 가져오기</button>
<ul>
{todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
async-await code
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
const fetchTodosFromFakeServer = async () => {
try {
setTodos(res.data);
} catch (error){
console.log(error);
}
};
useEffect(() => {
fetchTodosFromFakeServer()
},[]);
if (!todos) {
return <h1>데이터 없음</h1>;
}
return (
<>
<h1>todo list</h1>
<button onClick={fetchTodosFromFakeServer}>다시 가져오기</button>
<ul>
{todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchTodosFromFakeServer = async () => {
try {
setLoading(true);
setTodos(res.data);
console.log('tetch ok..');
} catch (error){
console.log(error);
setError(error);
}
setLoading(false);
};
useEffect(() => {
fetchTodosFromFakeServer()
},[]);
if(loading) return <div>로딩중..</div>
if(error) return <div>에러가 발생했습니다.</div>
if (!todos) return null;
return (
<>
<h1>todo list</h1>
<button onClick={fetchTodosFromFakeServer}>다시 가져오기</button>
<ul>
{todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todoStatus, setTodoStatus] = useState({
todos: null,
loading: false,
error: null,
});
const fetchTodosFromFakeServer = async () => {
try {
setTodoStatus({
...todoStatus,
loading: true,
});
setTodoStatus({
...todoStatus,
todos: res.data,
});
console.log('tetch ok..');
} catch (error){
console.log(error);
setTodoStatus({
...todoStatus,
error: error,
});
}
setTodoStatus({
...todoStatus,
loading: true,
});
};
useEffect(() => {
fetchTodosFromFakeServer()
},[]);
if(todoStatus.loading) return <div>로딩중..</div>
if(todoStatus.error) return <div>에러가 발생했습니다.</div>
if(!todoStatus.todos) return null;
return (
<>
<h1>todo list</h1>
<button onClick={fetchTodosFromFakeServer}>다시 가져오기</button>
<ul>
{todoStatus.todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
import { useState } from "react";
function Counter(){
const [number, setNumber] = useState(0);
const increaseNumber = () => setNumber(prev => prev + 1);
const decreaseNumber = () => setNumber(prev => prev - 1);
return (
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<h3>{number}</h3>
</div>
);
}
export default Counter;
==============================>
import { useReducer } from "react";
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>
</>
);
}
export default Counter;
==============================>
import { useReducer } from "react";
function reducer(status, action) {
switch (action.type) {
case 'INCREASE':
return {count: status.count + 1};
case 'DECREASE':
return {count: status.count - 1};
default:
return status;
};
}
function Counter() {
const [status, dispatch] = useReducer(reducer, {
count: 0,
});
const increaseNumber = () => dispatch({ type: 'INCREASE'} );
const decreaseNumber = () => dispatch({ type: 'DECREASE'} );
return (
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<h3>{status.count}</h3>
</div>
);
}
export default Counter;
==============================>
==============================>
import axios from "axios";
import { useEffect, useReducer } from "react";
function reducer(status, action) {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null,
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null,
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error,
};
default:
throw new Error(`unknown type ${action.type}`);
}
}
function App() {
const [status, dispatch] = useReducer(reducer, {
data: null,
loading: false,
error: null,
});
// const [todos, setTodos] = useState(null);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState(null);
// const [todoStatus, setTodoStatus] = useState({
// todos: null,
// loading: false,
// error: null,
// });
const fetchTodosFromFakeServer = async () => {
try {
dispatch({type: 'LOADING'});
dispatch({type: 'SUCCESS', data: res.data});
console.log('fetch ok..');
} catch (error) {
console.log(error);
dispatch({type: 'ERROR', error: error});
}
};
useEffect(() => {
fetchTodosFromFakeServer()
}, []);
const {loading, error, data: todos} = status;
if (loading) return <div>로딩중..</div>
if (error) return <div>에러가 발생했습니다.</div>
if (!todos) return null;
return (
<>
<h1>todo list</h1>
<button onClick={fetchTodosFromFakeServer}>다시 가져오기</button>
<ul>
{todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default App;
==============================>
App.js
import axios from "axios";
import { useEffect, useReducer } from "react";
import NewTodo from "./components/NewTodo";
import TodoList from "./components/TodoList";
function reducer(state, action) {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null,
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null,
};
case 'APPEND':
return{
loading: false,
error: null,
data: [
action.data,
...state.data,
]
}
return null;
case 'ERROR':
return {
loading: false,
data: null,
error: action.error,
};
default:
throw new Error(`unknown type ${action.type}`);
}
}
function App() {
const [state, dispatch] = useReducer(reducer, {
data: null,
loading: false,
error: null,
});
// const [todos, setTodos] = useState(null);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState(null);
// const [todoStatus, setTodoStatus] = useState({
// todos: null,
// loading: false,
// error: null,
// });
const fetchTodosFromFakeServer = async () => {
try {
dispatch({type: 'LOADING'});
dispatch({type: 'SUCCESS', data: res.data});
console.log('fetch ok..');
} catch (error) {
console.log(error);
dispatch({type: 'ERROR', error: error});
}
};
const appendNewTodoHandler = e => {
console.log('아버지가 할일 데이터 받았어요.. ', e);
const todoToAppend = {
id: parseInt(e.todoId),
title: e.body,
completed: false,
};
// state 에 추가하면 됨
//TODO
dispatch({type: 'APPEND', data: todoToAppend, })
};
useEffect(() => {
fetchTodosFromFakeServer()
}, []);
const {loading, error, data: todos} = state;
if (loading) return <div>로딩중..</div>
if (error) return <div>에러가 발생했습니다.</div>
if (!todos) return null;
return (
<>
<h1>todo list</h1>
<NewTodo onTodoAdded={appendNewTodoHandler}/>
<TodoList todos={todos} />
</>
);
}
export default App;
NewTodo.js
import { useState } from "react";
function NewTodo(props) {
const [todoId, setTodoId] = useState(0);
const [body, setBody] = useState('');
const idTextChangeHandler = (e) => {
console.log(e.target.value);
setTodoId(e.target.value);
}
const todoBodyChangeHandler = e => {
console.log(e.target.value);
setBody(e.target.value);
}
const formSubmitHandler = e => {
e.preventDefault();
console.log(todoId, body);
props.onTodoAdded({todoId, body});
}
return (
<>
<form onSubmit={formSubmitHandler}>
<div>
todo id : <input type='text' onChange={idTextChangeHandler}></input>
</div>
<div>
할일 : <input type='text' onChange={todoBodyChangeHandler}></input>
</div>
<div>
<input type='submit' value='할일 추가하기'></input>
</div>
</form>
</>
);
}
export default NewTodo;
TodoList.js
function TodoList(props) {
return (
<>
{/* <button onClick={fetchTodosFromFakeServer}>다시 가져오기</button> */}
<ul>
{props.todos.map(todo =>
<li key={todo.id}>
{todo.id}번 할일 : {todo.title} ({todo.completed ? '완료' : '미완료'})
</li>
)}
</ul>
</>
);
}
export default TodoList;
==============================>
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import Counter from './Counter';
import reportWebVitals from './reportWebVitals';
import CountProvider from './contexts/CountProvider';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<>
<CountProvider>
<Counter />
</CountProvider>
</>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
reportWebVitals();
CounterProvider.js
import { createContext, useState } from "react";
export const CountContext = createContext({
number: 0,
increaseNumber: () => {},
decreaseNumber: () => {},
});
function CountProvider({children}) {
const [count, setCount] = useState(0);
return(
<CountContext.Provider
value={{
number: count,
increaseNumber: () => { setCount(prev => prev + 1) },
decreaseNumber: () => { setCount( prev => prev - 1)} ,
}}>
{children}
</CountContext.Provider>
);
}
export default CountProvider;
Counter.js
import { useContext, useState } from "react";
import { CountContext } from "./contexts/CountProvider";
function Counter(){
const ctx = useContext(CountContext);
return (
<div>
<button onClick={ctx.increaseNumber}>+</button>
<button onClick={ctx.decreaseNumber}>-</button>
<h3>{ctx.number}</h3>
</div>
);
}
export default Counter;
Counter.js
import { useContext, useState } from "react";
import { CountContext } from "./contexts/CountProvider";
function Counter(){
const { number, increaseNumber, decreaseNumber} = useContext(CountContext);
return (
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<h3>{number}</h3>
</div>
);
}
export default Counter;
==============================>
custom hook
App.js
import axios from "axios";
import NewTodo from "./components/NewTodo";
import TodoList from "./components/TodoList";
import useAsync from "./hooks/useAsync";
function App() {
const fetchTodosFromFakeServer = async () => {
return res.data;
};
const [state] = useAsync(fetchTodosFromFakeServer, []);
const appendNewTodoHandler = e => {
};
const {loading, error, data: todos} = state;
if (loading) return <div>로딩중..</div>
if (error) return <div>에러가 발생했습니다.</div>
if (!todos) return null;
return (
<>
<h1>todo list</h1>
<NewTodo onTodoAdded={appendNewTodoHandler}/>
<TodoList todos={todos} />
</>
);
}
export default App;
useAsync.js
import { useEffect, useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null,
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null,
};
case 'APPEND':
return{
loading: false,
error: null,
data: [
action.data,
...state.data,
]
}
return null;
case 'ERROR':
return {
loading: false,
data: null,
error: action.error,
};
default:
throw new Error(`unknown type ${action.type}`);
}
}
function useAsync(callback, deps = []) {
const [state, dispatch] = useReducer(reducer, {
data: null,
loading: false,
error: null,
});
const fetchData = async () => {
dispatch({type: 'LOADING'})
try{
const data = await callback();
dispatch({type: 'SUCCESS', data});
} catch (e) {
dispatch({type: 'ERROR'});
}
};
useEffect(() => {
fetchData();
}, deps);
return [state, fetchData];
}
export default useAsync;
==============================>
SPA Deploy
-> npm run build
-> npm install -g firebase-tools
-> firebase login
-> firebase init
-> firebase deploy
==============================>
댓글