Front-end/React

React 기초(todoList)- AWS 풀스택 과정 40일차

awspspgh 2024. 9. 9. 18:01

오늘은 todoList를 만들어보겠습니다.

 

목차
1. todoList
2. axios
3. 느낀 점

 

1. todoList

- App.js

import './App.css';
import TodoList from './component/TodoList';
import './component/createTodo.css';

function App() {
  return (
    <div className="App">
      <div className='title'>TodoList</div>
      <TodoList />
    </div>
  );
}

export default App;

 

- Todo.jsx

import React from 'react';
import './createTodo.css';

const Todo = ({ user, onRemove, onToggle }) => {
    return (
        <div className='TodoContainer'>
            <div className='TodoBody'>
                <span className='TodoUser' style={{
                    cursor: 'pointer',
                    textDecorationLine: user.active ? 'line-through' : 'none'
                }} onClick={() => onToggle(user.id)}> {user.username}</span>
            </div>
                <button className='delButton' onClick={() => onRemove(user.id)}>X</button>
        </div>
    );
};

export default Todo;

 

- CreateTodo.jsx

import React from 'react';
import './createTodo.css';

const CreateTodo = ({ username, onChange, onCreate }) => {
    return (
        <div className='createName'>
            <input
            className='todoInput'
            type="text" 
            name='username'
            onChange={onChange}
            value={username}
            />
            <button className='createButton' onClick={onCreate}>create</button>
        </div>
    );
};

export default CreateTodo;

 

- TodoList.jsx

import React, { useRef, useState } from 'react';
import Todo from './Todo';
import CreateTodo from './CreateTodo';
import './createTodo.css';

const TodoList = () => {

    const nextId = useRef(1);

    const [users, setUsers] = useState([]);
    
    const [ inputs, setInputs ] = useState({
        username : '',
    });

    const { username } = inputs;
    
    const onChange = (e) => {
        const { name, value } = e.target;
        setInputs({
            ...inputs,  
            [name]:value  
        });
        console.log(inputs);
    }

    const onCreate = ()=>{
        const user = {
            id: nextId.current,
            username: username,
        }
        setUsers(users.concat(user));

        setInputs({
            username:'',
        })

        nextId.current += 1 ;
        console.log(users);
    
    }

    const onRemove = (id) => {
        setUsers(users.filter(user => user.id !== id));
    }

    const onToggle = (id) => {
        setUsers(users.map(u=>
            u.id === id ? { ...u, active: !u.active} : u
        ))
    }

    return (
        <div className='userList'>
            <CreateTodo username={username} onChange={onChange} onCreate={onCreate}/>
            {
                users.map((u)=>(
                    <Todo user={u} key={u.id} onRemove={onRemove} onToggle={onToggle}/>
                ))
            }
        </div>
    );
};

export default TodoList;

 

- createTodo.css

.App{
    width: 1000px;
    margin: 0 auto;
}
.title{
    font-size: 70px;
    font-weight: 700;
    /* color 그라데이션 */
    background: linear-gradient(to right top, #861657, #ffa69e);
    color: transparent;
    -webkit-background-clip: text;
    margin-bottom: 30px;
}
.createName{
    width: 700px;
    height: 100px;
    margin: 0 auto;
    display: flex;
    justify-content: center;
    align-items: center;
    /* background-color: rgba(128, 128, 128, 0.075); */
    border-radius: 15px;
}
.todoInput{
    width: 250px;
    height: 35px;
    margin-right: 30px;
    color: purple;
    font-size: 25px;
    font-weight: 550;
    outline: none;
    /* border 그라데이션 */
    border: 2px solid transparent;
    border-radius: 15px;
    background-image: linear-gradient(#fff, #fff), linear-gradient(to right top, #861657, #ffa69e);
    background-origin: border-box;
    background-clip: content-box, border-box;
}
.createButton{
    width: 100px;
    height: 40px;
    color: white;
    font-size: 20px;
    font-weight: 300;
    /* border 그라데이션 - button */
    border: 1px solid transparent;
    border-radius: 20px;
    background-image: linear-gradient(to right top, #12c2e9, #c471ed, #f64f59);
    background-origin: border-box;
    background-clip: content-box, border-box;
}
.createButton:hover{
    cursor: pointer;
}
.TodoUser{
    font-size: 30px;
    font-weight: 550;
}
.TodoContainer{
    margin: 30px auto;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 550px;
    height: 80px;
    /* border 그라데이션 */
    border: 8px solid transparent;
    border-radius: 15px;
    background-image: linear-gradient(#fff, #fff), linear-gradient(to right top, #861657, #ffa69e);
    background-origin: border-box;
    background-clip: content-box, border-box;
}
.TodoContainer:nth-child(2n){
        /* border 그라데이션 */
        border: 8px solid transparent;
        border-radius: 15px;
        background-image: linear-gradient(#fff, #fff), linear-gradient(to left top, #861657, #ffa69e);
        background-origin: border-box;
        background-clip: content-box, border-box;
}
.TodoBody{
    width: 300px;
    height: 50px;
    border-radius: 10px;
    padding-left: 10px;
    display: flex;
    align-items: center;
    margin-right: 100px;
    color: #861657;
}
.delButton{
    width: 70px;
    height: 55px;
    font-size: 25px;
    font-weight: 550;
    border: 5px solid white;
    border-radius: 20px;
    /* color 그라데이션 */
    background: linear-gradient(to right top, #861657, #ffa69e);
    color: transparent;
    -webkit-background-clip: text;
}
.delButton:hover{
    width: 70px;
    height: 50px;
    color: white;
    /* border 그라데이션 - button */
    border: 1px solid transparent;
    border-radius: 20px;
    background-image: linear-gradient(to right top, #12c2e9, #c471ed, #f64f59);
    background-origin: border-box;
    background-clip: content-box, border-box;
}

 

▷ 출력

출력 (1)

 

2. axios

◈ useMemo

useMemo() => 리액트에서 컴포넌트 성능을 최적화 하는데 사용되는 훅
memo => memoization의 약자. 메모리에 넣기
동일한 계산을 반복해야 할 떄, 이전에 값을 메모리에 저장함으로써
반복수행을 제거하여 프로그램 실행 속도를 빠르게 해주는 기술

함수형 컴포넌트가 랜더링 => 컴포넌트 함수 호출 => 모든 내부 변수 초기화

useMemo 랜더링 => 함수 호출 => memoize된 함수를 재사용

 

◈ axios

■ axios(외장 라이브러리 별도 설치 필요) 
  => js ajax(js 내장 라이브러리)

- url : 요청 주소
- method : get(요청), post(삽입), put 또는 patch(수정), delete(삭제)

response : 응답 객체
request : 요청 객체
axios.get( url [, config] )
axios.post( url [, config] [, data] )
axios.put( url [, config] [, data] )
axios.delete( url [, config] )

■ useEffect() : hook
- 컴포넌트가 랜더링 될 때, 혹은 업데이트 될 때 실행되는 hook
useEffect((function), deps)
- function : 실행시킬 함수
- deps : 배열형태
- [] 빈배열 : 마운트 될 때만 실행
- x : 매번 랜더링 될 때마다 실행 
- [name] : 업데이트 될 때마다 실행

 

▶ 입력

npx create-react-app axios-app

cd axios-app

npm i axios (=> axios 설치)

 

※ jsonplaceholder

https://jsonplaceholder.typicode.com/users

 

- App.js

import './App.css';
import User from './component/User';

function App() {
  return (
    <div className="App">
      <User />
    </div>
  );
}

export default App;

 

- User.jsx

import React from 'react';
import { useState } from 'react';
// import { useEffect } from 'react';
import axios from 'axios';

const User = () => {
    
    const [ users, setUsers ] = useState([]);
    // 다운로드가 잘 되었는지 확인용 / 에러 확인용
    const [ loading, setLoading ] = useState(false);
    const [ error, setError ] = useState(null);

    const fetchUsers = async () => {   
            try{
                // 요청이 시작되면 loading의 상태를 true로 변경
                setLoading(true);
                const response = await axios.get('https://jsonplaceholder.typicode.com/users');
                console.log(response);
                setUsers(response.data);  // data는 response.data 안에 담겨있음.
            }catch(e){
                setError(e);
            }
            setLoading(false);
    }

    // useEffect(() => {
    //     fetchUsers();
    // },[]);

    if(loading) return <div>로딩중...</div>;
    if(error) return <div>에러가 발생했습니다.</div>
    // if(!users) return <div>User null!!!</div>

    return (
        <div className='user'>
            <div>User.jsx 영역</div>
            <ul>
                {
                    users.map(user => (
                        <li key={user.id}>{user.username} ({user.name})</li>
                    ))
                }
            </ul>
            {/* button을 추가하여 클릭시 user 데이터가 뜰 수 있도록 설정 */}
            <button onClick={fetchUsers}>데이터 불러오기</button>
        </div>
    );
};

export default User;

 

▷ 출력

출력 (2)

 

3. 느낀 점

예전에 css를 했을 때에는 정말 하기 싫었는데.. 오랜만에 해보니 너무 재미있어서 기분이 좋았다. 다른 수강생분들이 하신 todoList를 보면서 내가 어떤 기능을 새로 추가할 수 있을지 고민해봐야할 것 같다는 생각을 하게 되었다.