안랩샘아카데미 React로 시작하는 프론트엔드 7주차 정리

구나영·2024년 5월 6일
post-thumbnail

React Counter App
초기화하는 0버튼 만들어주고
onClickButton 이벤트 변경해주기

App.jsx

const onClickButton = (value) => {
    if(value){
      setCount(count + value);
    } else {
      setCount(0);
    }
  };

리액트 컴포넌트 라이프 사이클

Mount-탄생, 페이지에 나타남
Update-업데이트, State업데이트,Props업데이트,부모컴포넌트 리렌더
Unmount-죽음,페이지에서 사라짐(제거됨)

useEffect

  • 어떤 값이 변경될 때마다 특정 코드를 실행하는 리액트 훅
  • 라이프 사이클 제어, 특정 값을 검사한다라고 표현

useEffect(callback, [deps]);
callback->콜백함수, [deps]->의존성배열

count값 변경될 때마다 확인하는 useEffect 생성해서 콘솔로 확인해보기

App.jsx

import { useState, useEffect } from 'react';

useEffect(() => {
	console.log(`count: ${count}` );
}, [count]);    

input 추가해서 확인해보기

App.jsx

const [input, setInput] = useState("");

useEffect(() => {
	console.log(`count: ${count}`, `input: ${input}`);
}, [count, input]);    

//React Counter App밑에 input 표시하기
return (
      <div className="App">
       <h1>React Counter App</h1>
       <section>
          <input
            value={input}
            onChange={(e) => {
              setInput(e.target.value);
            }}>
          </input> 
        </section>  
        ...

App.jsx

 //1. 마운트(처음 렌더링될때만 실행되게 의존성배열을 빈배열로 넣어준다)
  useEffect(()=>{
    console.log("마운트 되었음");
  }, []);

  //2. 업데이트(리렌더링될때마다 계속 실행되게 두번째인자 의존성배열생략,
  //특정스테이트변수 변화감지하고싶을경우 의존성배열에 감시하고싶은거만 넣어주기)
  useEffect(()=>{
    console.log("업데이트 되었음");
  });

업데이트 되었을 때만 업데이트 표시하기

App.jsx


  import { useState, useEffect, useRef } from 'react';
  
  const isMount = useRef(false);
  
  //2. 업데이트
  useEffect(()=>{
    if(!isMount.current){ 
      isMount.current = true;
      return
    }
    console.log("업데이트 되었음"); //마운트시점이 아닌 경우
  });
  1. 언마운트 연습-짝수일때만 짝수입니다 출력하는 짝수컴포넌트 Even.jsx 생성하기

App.jsx

import './App.css'
import { useState, useEffect, useRef } from 'react';
import Viewer from './components/Viewer';
import Controller from './components/Controller';
import Even from './components/Even';

function App() {
  const [count, setCount] = useState(0);
  const [input, setInput] = useState("");
  //console.log(count);

  // useEffect(() => {
  //   console.log(`count: ${count}, input: ${input}`);
  // }, [count, input]);

  const isMount = useRef(false);

  //1. 마운트(처음 렌더링될때만 실행되게 의존성배열을 빈배열로넣어준다)
  useEffect(()=>{
    console.log("마운트 되었음");
  }, []);

  //2. 업데이트(리렌더링될때마다 계속 실행되게 두번째인자 의존성배열생략,
  //특정스테이트변수 변화감지하고싶을때에는 의존성배열에 감시하고싶은거만 넣어주기)
  useEffect(()=>{
    if(!isMount.current){
      isMount.current = true;
      return
    }
    console.log("업데이트 되었음");
  });


//이벤트핸들러 사용하기
  const onClickButton = (value) => {
    if(value){
      setCount(count + value);
    } else {
      setCount(0);
    }
  };
  return (
      <div className="App">
       <h1>React Counter App</h1>
       <section>
          <input
            value={input}
            onChange={(e) => {
              setInput(e.target.value);
            }}>
          </input> 
        </section>  
       <section>
       <Viewer count={count}/>
       {count %2 === 0? <Even /> : null}
       </section>
       <section>
       <Controller onClickButton = {onClickButton} />
       </section>
      </div>  
  );
}

export default App;

1초마다 깜빡 메세지 출력하기(언마운트되면 깜박이지않게하기)

Even.jsx

import { useEffect } from "react";

const Even = () => {
    useEffect(() => {
        console.log("이븐 컴포넌트 마운트");
        
        const intervalID = setInterval(()=>{
            console.log("깜박");
        }, 1000);
            
        return () => { //클린업함수(정리함수)
            console.log("이븐 컴포넌트 언마운트");
            clearInterval(intervalID); //언마운트되면 깜박하지않게
        }
    }, [])
    return <div>짝수입니다!!!</div>
};

export default Even;

크롬 웹스토어에서 React Developer Tools 확장프로그램 설치

->확장프로그램관리에서 켜져있는지확인하고 세부정보 확인하고 아래항목 켜기

크롬개발자도구 >>클릭하고 Components,Profiler 안보이면

Restore defaults and reload 실행해주면된다.

리액트로 만드는 TodoList 앱 프로젝트-todolistapp

  • 프로젝트 기획하기
  • UI 구현하기
  • 기능 구현
  • 할일 추가하기
  • 할일리스트 화면에 렌더링하기
  • 할일 수정하기
  • 할일 삭제하기

요구사항 분석

  • 오늘의 날짜를 요일, 월, 일, 연도순으로 표시
  • 할일(Todo)을 작성하는 입력 폼이 있고, [추가] 버튼을 클릭하면 할 일 아이템을 생성
  • 생성한 아이템을 페이지 하단에 리스트로 표시
  • 키워드 검색으로 원하는 할 일 리스트 추출 가능
  • 각각의 할일 아이템은 일을 마쳤는지 여부를 표시하는 체크박스, 아이템 이름, 등록
    날짜, [삭제] 버튼으로 구성

컴포넌트 단위

  • Header: 오늘의 날짜를 표시 형식에 맞게 보여주기
  • Editor: 새로운 할 일 아이템 입력
  • List: 검색어에 맞게 필터링된 할 일 리스트를 렌더링해서 보여주기
    (검색폼이 공란이면 필터링 하지 않기!)
  • TodoItem: 각각의 할 일 아이템에는 아이템 정보과 체크박스와 [삭제] 버튼을 가짐.
    체크박스를 클릭하면 할 일을 마쳤는지 여부가 토글
    [삭제]버튼을 클릭하면 해당 아이템 삭제

components 디렉토리만들어서 그 안에 Header.jsx,Editor.jsx,List.jsx 만들기
List.jsx

const List = () => {
	return <div>List</div>
};

export default List;

위와 같은 형식으로 만들어주고 App으로 가져오기
App.jsx

import './App.css';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

function App() {
  return (
      <div className="App">
        <Header />
        <Editor/>
        <List/>
      </div>  
  );
}

export default App;

App.jsx에서 className주고 App.css에서 외부스타일링하기

.App {
    width: 500px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

오늘날짜 표시하는 헤더 만들기
Header.jsx(이모티콘은 윈도우키+.으로 입력하기)

import "./Header.css";

const Header = () => {
    return (
    <div className="Header">
       <h3>오늘은...🕰</h3>
       <h1>{new Date().toDateString()}</h1>
    </div>
    );
};

export default Header;

Header.css

.Header h1 {
    color: blueviolet;
}

할일 추가하는 에디터 만들기
Editor.jsx

import "./Editor.css";

const Editor = () => {
   return (
    <div className="Editor">
        <input placeholder="새로운 할일..."/>
        <button>추가</button>
        </div>
    );
};

export default Editor;

Editor.css

.Editor {
    display: flex;
    gap: 10px;
}

.Editor input {
    flex: 1;
    padding: 15px;
    border: 1px solid rgb(220, 220, 220);
    border-radius: 5px;
}

.Editor button {
    cursor: pointer;
    width: 80px;
    border: none;
    background-color: blueviolet;
    color: white;
    border-radius: 5px;
}

할일리스트 보여주는 리스트 만들기
List.jsx

import "./List.css";

const List = () => {
    return <div className="List">
        <h4>🎈Todo List...🎈</h4>
        <input placeholder="검색어를 입력하세요" />
    </div>
};

export default List;

List.css

.List {
    display: flex;
    flex-direction: column;
    gap: 20px;
}


.List input {
    width: 100%;
    border: none;
    border-bottom: 1px solid rgb(220,220,220);
    padding: 15px 0px;
}

.List input:focus {
    outline: none;
    border-bottom: 1px solid rgb(153,185,250);
}

할일리스트에 들어가는 할일아이템 만들기
TodoItem.jsx

import "./TodoItem.css"

const TodoItem = () => {
return  <div>todoItem</div>;
};

export default TodoItem;

리스트에서 아이템 렌더링해서 보여주기
List.jsx

import "./List.css"
import TodoItem from "./TodoItem";

const List = () => {
    return <div className="List">
        <h4>🎈Todo List...🎈</h4>
        <input placeholder="검색어를 입력하세요" />
        <div className="todos_wrapper">
         <TodoItem/>
         <TodoItem/>
         <TodoItem/>
        </div>
    </div>
};

export default List;

기본형태만들어주기
TodoItem.jsx

import "./TodoItem.css"

const TodoItem = () => {
return  <div className="TodoItem"><input type="checkbox" />
<div className="content">할일</div>
<div className="date">날짜</div>
<button>삭제</button>
</div>;
};

export default TodoItem;

TodoItem.css

.TodoItem {
    display: flex;
    align-items: center;
    gap: 20px;
    padding-bottom: 20px;
    border-bottom: 1px solid rgb(220,220,220);
}

.TodoItem input {
    width: 20px;

}

.TodoItem .content {
    flex: 1;
}

.TodoItem .date {
    color: gray;
    font-size: 14px;
}

.TodoItem button {
    cursor: pointer;
    color: gray;
    font-size: 14px;
    border: none;
    border-radius: 5px;
    padding: 5px;
}

List.jsx에서 스타일링하기위해 div에 className="todos_wrapper"주고
List.css에 todos_wrapper 추가해준다.

.List .todos_wrapper {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

todos State 만들기
const [todos, setTodos] = useState([]); ->여러개의 할 일을 관리하기위해 빈배열로 초기화, testData를 useState에 넣어준다.
App.jsx

import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

const testData = [
  {
  id:0,
  isDone: false,
  content: "React 공부하기",
  date: new Date().getTime(),
  },
  {
    id:1,
    isDone: false,
    content: "밥먹기",
    date: new Date().getTime(),
  },
  {
    id:2,
    isDone: false,
    content: "운동하기",
    date: new Date().getTime(),
  },

];

function App() {
  const [todos, setTodos] = useState(testData);
  const idRef = useRef(3);

  return (
      <div className="App">
        <Header />
        <Editor/>
        <List/>
      </div>  
  );
}

export default App;

App컴포넌트에서 testData 제대로 들어갔는지 개발자도구로 확인해보기

추가버튼눌렀을때 새로운 할 일 생성해서 보여주는 함수 onCreate 만들고
Editor에 onCreate props 전달해주기
App.jsx

import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

const textData = [
  {
  id:0,
  isDone: false,
  content: "React 공부하기",
  date: new Date().getTime(),
  },
  {
    id:1,
    isDone: false,
    content: "밥먹기",
    date: new Date().getTime(),
  },
  {
    id:2,
    isDone: false,
    content: "운동하기",
    date: new Date().getTime(),
  },

];

function App() {
  const [todos, setTodos] = useState(textData);
  const idRef = useRef(3);

  const onCreate = (content) => {
    const newTodo = {
      id: idRef.current++,
      isDone: false,
      content: content,
      date: new Date().getTime(),
    };

    setTodos([newTodo,...todos]);

  };

  return (
      <div className="App">
        <Header />
        <Editor onCreate={onCreate} />
        <List/>
      </div>  
  );
}

export default App;

Editor에서 onCreate를 props로 전달받아서 onSubmit 이벤트핸들러 만들어서
onCreate 호출되도록 만들어서 추가버튼 onClick이벤트에 onSubmit 이벤트핸들러 등록하기,
input값 보관하기위한 state 생성하고 변화가생기면 state값을 갱신해줄 onChangeContent 만들어서 OnChange이벤트에 등록하기

Editor.jsx

import "./Editor.css";
import { useState } from "react";

const Editor = ({ onCreate }) => {
    const [content,setContent] = useState("");

    const onChangeContent = (e) => {
        setContent(e.target.value);  
    };

    const onSubmit = () => {
        onCreate(content);
    }

    return (
    <div className="Editor">
        <input
        value={content}
        onChange={onChangeContent}
        placeholder="새로운 할일..."/>
        <button onClick={onSubmit}>추가</button>
        </div>
    );
};

export default Editor;

할일 추가하면 todo State에 잘 들어가는지 개발자도구로 확인하기

아이디다루기위해서 useRef 만들어준다. useRef 이용해서 아이디값 증가하게한다.
App.jsx

import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

const testData = [
  {
  id:0,
  isDone: false,
  content: "React 공부하기",
  date: new Date().getTime(),
  },
  {
    id:1,
    isDone: false,
    content: "밥먹기",
    date: new Date().getTime(),
  },
  {
    id:2,
    isDone: false,
    content: "운동하기",
    date: new Date().getTime(),
  },

];

function App() {
  const [todos, setTodos] = useState(testData);
  const idRef = useRef(3);

  const onCreate = (content) => {
    const newTodo = {
      id: idRef.current++,
      isDone: false,
      content: content,
      date: new Date().getTime(),
    };

    setTodos([newTodo,...todos]);

  };



  return (
      <div className="App">
        <Header />
        <Editor onCreate={onCreate} />
        <List />
      </div>  
  );
}

export default App;

추가할때 입력이 비어있다면 onCreate호출안하고 추가안되게하고 포커스주기
(포커스주기위해 useRef 사용)
, 추가후 빈칸으로 초기화하기, 추가할때 엔터로 추가되게 하는 onKeyDown추가
Editor.jsx

import "./Editor.css";
import { useState, useRef } from "react";

const Editor = ({ onCreate }) => {
    const [content,setContent] = useState("");
    const contentRef = useRef();

    const onChangeContent = (e) => {
        setContent(e.target.value);  
    };

    const onKeyDown = (e) => { //엔터이벤트
        if(e.keyCode === 13){
            onSubmit();
        }
    };

    const onSubmit = () => {
        if(content===""){
            contentRef.current.focus(); //포커스주기
            return;//비어있다면 추가버튼 눌러도 들어가지않게한다.
        }
        onCreate(content);
        setContent(""); //추가후 초기화
    }

    return (
    <div className="Editor">
        <input
        ref={contentRef}
        value={content}
        onKeyDown={onKeyDown}
        onChange={onChangeContent}
        placeholder="새로운 할일..."/>
        <button onClick={onSubmit}>추가</button>
        </div>
    );
};

export default Editor;

List에 todos props로 전달해주고 map함수이용해서 List 렌더링해서 보여주기
List.jsx

import "./List.css";
import TodoItem from "./TodoItem";

const List = ({ todos }) => {
    return (
    <div className="List">
        <h4>🎈Todo List...🎈</h4>
        <input placeholder="검색어를 입력하세요" />
        <div className="todos_wrapper">
           {todos.map((todo) => {
           return <TodoItem {...todo} />
        })}
        </div>
    </div>
    );
};

export default List;

List에 todos props 전달되어있고 데이터들어가있는지 개발자도구로 확인할 수 있다.

List에서 던진 props todo 사용해서 화면에 렌더링해준다.

TodoItem.jsx

import "./TodoItem.css"

const TodoItem = ({id, isDone, content, date }) => {

    const onChangeCheckBox = () => {
        onUpdate(id);
    };

    const onClickDeleteButton = () => {
        onDelete(id);
    }

    return (
     <div className="TodoItem">
    <input checked={isDone} type="checkbox" />
<div className="content">{content}</div>
<div className="date">{new Date(date).toLocaleDateString()}</div>
<button>삭제</button>
</div>
);
};

export default TodoItem;

0개의 댓글