본문 바로가기
푸닥거리

axios promise async-await useEffect useReducer Hook react

by [김경민]™ ┌(  ̄∇ ̄)┘™ 2022. 5. 21.
728x90



화면에 바인딩(렌더링)되는 데이타
- 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 {
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');      
      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);
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');      
      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,
      });
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');      
      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'});
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');
      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'});
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');
      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))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
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 () => {    
      const res = await axios.get('https://jsonplaceholder.typicode.com/todos');
      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

 

==============================>

 

 

 

 

728x90

댓글