관리 메뉴

공부기록용

React입문 1주차(정리&LV1과제) 본문

📚강의록📚/스파르타)React

React입문 1주차(정리&LV1과제)

과부하가즈아 2023. 6. 28. 13:16

import

import React from "react";

 

여기서 `React`는 React 라이브러리에서 내보내는 기본 모듈입니다. 대부분의 경우, React 라이브러리에서 `React` 객체를 사용하여 React 컴포넌트를 생성하고 JSX를 렌더링하는 데 필요한 기능을 사용할 수 있습니다.

또 구조 분해 할당을 사용하여 필요한 기능을 선택적으로 가져올 수도 있습니다. 예를 들어, `useState`와 `useEffect` 훅을 가져오려면 다음과 같이 작성할 수 있습니다:

import React, { useState, useEffect } from "react";

 

> `React`와 함께 `useState`와 `useEffect`를 현재 파일에서 사용할 수 있도록 가져옵니다. 이렇게 하면 `React.useState` 대신에 `useState`와 같이 직접 사용할 수 있습니다.

 


또한, React 라이브러리 외에도 추가적인 모듈이 필요한 경우 해당 모듈도 `import` 구문을 사용하여 가져올 수 있습니다. 예를 들어, React 컴포넌트에서 CSS 스타일을 사용하려면 다음과 같이 작성할 수 있습니다:

import React from "react";
import "./App.css";

 

> 현재 파일에 있는 `App.css` 파일에서 정의된 CSS 스타일을 가져옵니다. 이렇게 하면 JSX 요소에 CSS 클래스를 적용할 수 있게 됩니다.

`import` 구문은 필요한 모듈이나 라이브러리를 현재 파일에 가져와서 사용할 수 있도록 해줍니다. React에서는 `React` 모듈을 가져와서 React 컴포넌트를 작성하고 JSX를 사용하는 데 필요한 기능을 사용할 수 있게 됩니다.


component

import React, { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default Counter;
import React, { useState } from "react";: React와 useState를 import하여 해당 기능을 사용할 수 있도록 합니다. useState는 상태(state)를 관리하기 위해 사용됩니다.

const Counter = () => { ... }
: Counter라는 이름의 함수형 컴포넌트를 정의합니다. 이 컴포넌트는 기능을 구현하고 JSX를 반환합니다.

const [count, setCount] = useState(0);
: count라는 상태 변수와 setCount라는 상태 변경 함수를 useState 훅을 사용하여 선언합니다. count는 현재의 카운트 값을 저장하고, setCount는 카운트 값을 변경하는 데 사용됩니다. 초기 카운트 값은 0으로 설정됩니다.

const incrementCount = () => { ... }
: incrementCount라는 함수를 정의합니다. 이 함수는 클릭 이벤트가 발생할 때마다 카운트 값을 1씩 증가시킵니다. setCount 함수는 이전 카운트 값을 가져와 1을 더한 새로운 값을 설정합니다. 함수형 업데이트를 사용하여 이전 상태 값을 직접 참조하고 변경할 수 있습니다.
>> prevCount말고 다른 어떤걸 써도 되고 보통 count할텐데 이미 위에있는 useState에서 count사용해서 다르게 한것(겹치면 아주아주 헷갈리니까 다르게 하기 꼭!)

JSX를 사용하여 컴포넌트의 UI를 반환합니다.
<p>Count: {count}</p>는 현재 카운트 값을 표시하는 부분이며,
<button onClick={incrementCount}>Increment</button>은 클릭 이벤트가 발생할 때 incrementCount 함수를 호출하여 카운트 값을 증가시키는 버튼입니다.

export default Counter;: Counter 컴포넌트를 외부에서 사용할 수 있도록 export합니다.

props

React 컴포넌트 간에 데이터를 전달하기 위해 사용되는 객체입니다. props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용

// 부모 컴포넌트
const ParentComponent = () => {
  const name = "John";
  return <Greeting name={name} />;
};

// 자식 컴포넌트
const Greeting = (props) => {
  return <p>Hello, {props.name}!</p>;
};

> ParentComponentGreeting 컴포넌트를 사용

> Greeting 컴포넌트에 name 속성을 전달하고 있으며, props 객체를 통해 해당 속성에 접근

> Greeting 컴포넌트는 전달받은 name 속성을 출력하여 "Hello, John!"이라는 결과를 렌더링


import { useState } from "react"

const Sample = () => {
    const [names,setNames] = useState([
        {id:1, text:'가나'},
        {id:2, text:'다라'},
        {id:3, text:'마바'},
        {id:4, text:'사아'},
    ])
    
    const [inputText, setInputText] = useState('')
    
    const [nextId, setNextId] = useState(5)
    
    const changeHandler = (e) => setInputText(e.target.value)
    
    const clickHandler = () => {
        const newName = names.concat({
            id: nextId,
            text: inputText
        })
        setNextId(nextId + 1)
        setNames( newName )
        setInputText('')
    }

    const nameList = names.map(name => <li key={name.id}>{name.text}</li> )

    return (
        <div>
            <input type="text" value={inputText} onChange={changeHandler} />
            <button onClick={clickHandler}>추가</button>
            <ul>{nameList}</ul>
        </div>
    )
}

export default Sample

먼저, useState 훅을 사용하여 상태를 관리합니다. names는 항목의 배열을 저장하며, 초기값으로 4개의 객체가 포함된 배열을 가지고 있습니다.

 

inputText는 입력 필드의 텍스트 값을 저장하고, nextId는 다음 항목의 고유 ID를 지정합니다.

 

changeHandler 함수는 입력 필드의 변경 이벤트를 처리하여 inputText 상태를 업데이트합니다.

 

clickHandler 함수는 추가 버튼의 클릭 이벤트를 처리합니다. 새로운 항목을 생성하여 names 배열에 추가하고, nextId를 업데이트하여 다음 항목에 사용할 고유 ID를 증가시킵니다. 마지막으로, inputText를 빈 문자열로 초기화합니다.

 

nameList 변수는 names 배열을 map 함수를 사용하여 각 항목을 <li> 요소로 변환한 배열입니다. 각 요소에는 key 속성으로 name.id가 사용되며, 이는 React에서 배열의 요소를 업데이트하고 구별하는 데 도움을 줍니다.

 

컴포넌트의 반환부는 입력 필드, 추가 버튼, <ul> 요소로 구성됩니다. 입력 필드는 inputText 상태와 연결되어 현재 값을 표시하고, onChange 이벤트에는 changeHandler 함수가 할당됩니다. 추가 버튼은 onClick 이벤트에 clickHandler 함수가 할당되어 클릭 이벤트를 처리합니다. <ul> 요소 내부에는 nameList 배열이 렌더링되어 동적으로 항목이 추가됩니다.

 

출처 : https://nayoungkim00.tistory.com/46


import React, { useState } from "react"; // useState를 import해주는 것 확인
import './App.css';

function App(){

  const [todos, setTodos] = useState([
    { id: 1, title: '1주 과제', body: '과제끝내기!', isDone: false },
    { id: 2, title: '1주 강의', body: '강의 수강 완료하기!', isDone: true },
  ]);


  // 제목
  const [title, setTitle] = useState('');

  // 내용
  const [body, setBody] = useState('');

  // 제목과 내용 
  const titleChangeHandler = (event) => {
    setTitle(event.target.value)
  }
  const bodyChangeHandler = function (event) {
    setBody(event.target.value)
  }

  // 추가 
  const clickAddBtnHandler = function (event) {

    const newTodo = {
      id: todos.length + 1,
      title,
      body,
      isDone: false,
    };

    // ✨불변성 유지
    setTodos([...todos, newTodo]);

  };


  // 삭제
  const clickRemoveBtnHandler = (id) => {
    const newTodo = todos.filter(function (todos) {
      return todos.id !== id;
    })
    setTodos(newTodo);
  }

  // 완료 취소
  const doneTodoHandler = (id) => {
    const newTodoList = todos.map((todo) => {
      if (todo.id === id) return { ...todo, isDone: !(todo.isDone) };  // todo, todos 확인
      return todo;
    });
    setTodos(newTodoList);
  }

  return (
    <div>

      <div className="container">
        <div>My Todo List</div>
        <div>React</div>
      </div>


      <div className="add-group">
        <div className="input-group">
          <label className="label">제목</label>

          <input
            value={title}
            onChange={(event) => titleChangeHandler(event)}
            type="text" name="body" className="add-input" />


          <label className="label">내용</label>
          <input
            value={body}
            onChange={bodyChangeHandler}
            type="text" name="body" className="add-input" />
        </div>

        <Button clickAddBtnHandler={clickAddBtnHandler} />
      </div>


      <div className="list-container">

        <h2 className="list-title">ing ✨</h2>
        <div className="list-wrapper">
          {todos.filter((todo) => todo.isDone === false).map((todo) => {
            return (
              <div key={`ing-${todo.id}`} className='todo-container'>

                <h2 className="todo-title">{todo.title}</h2>
                <div>{todo.body}</div>

                <div className="button-set">
                  <button 
                    key={todo.id}
                    todo={todo}
                    className="todo-delete-button button"
                    onClick={()=>clickRemoveBtnHandler(todo.id)}>삭제</button>
                    
                  <button
                    key={todo.id}
                    todo={todo}
                    className="todo-delete-button button"
                    onClick={() => doneTodoHandler(todo.id)}>완료</button>
                    
                </div>
              </div>
            )
          })}
        </div>
      </div>


      <div className="list-container">
        
        <h2 className="list-title">Done👌</h2>
        <div className="list-wrapper">
          {todos.filter((todo) => todo.isDone === true).map((todo) => {
              return (
                <div key={`done-${todo.id}`} className='todo-container'>

                  <h2 className="todo-title">{todo.title}</h2>
                  <div>{todo.body}</div>

                  <div className="button-set">
                    <button
                      key={todo.id}
                      todo={todo}
                      className="todo-delete-button button"
                      onClick={()=>clickRemoveBtnHandler(todo.id)}>삭제</button>
                      
                    <button
                      key={todo.id}
                      todo={todo}
                      className="todo-delete-button button"
                      onClick={() => doneTodoHandler(todo.id)}>취소</button>
                      
                  </div>
                </div>
              )
            })}
        </div>
      </div>

    </div>
  );
};

const Button = ({clickAddBtnHandler}) => {
  return <button onClick={clickAddBtnHandler} className="add-button">추가!</button>
}

export default App;

1. 상태 관리:

const [todos, setTodos] = useState([
    { id: 1, title: '1주 과제', body: '과제끝내기!', isDone: false }, // ing
    { id: 2, title: '1주 강의', body: '강의 수강 완료하기!', isDone: true }, // done
]);

 

- `todos`는 `useState` 훅을 사용하여 Todo 항목들의 배열을 관리합니다. 

초기 상태로 두 개의 Todo 항목이 포함된 배열이 설정됩니다. 배열의 각 항목은 객체로 구성되어 있며, `id`, `title`, `body`, `isDone` 프로퍼티를 가지고 있습니다.

 

// 제목
const [title, setTitle] = useState('');

// 내용
const [body, setBody] = useState('');

 

- `title`과 `body`는 각각 `useState` 훅을 사용하여 Todo 항목의 제목과 내용을 관리합니다. 초기 값은 빈 문자열("")입니다.



2. 이벤트 핸들러:

// 제목과 내용 
const titleChangeHandler = (event) => {
  setTitle(event.target.value)
}
const bodyChangeHandler = function (event) {
  setBody(event.target.value)
}

 

- `titleChangeHandler`와 `bodyChangeHandler`는 입력 필드의 변경 이벤트를 처리하는 함수입니다. `event.target.value`를 사용하여 입력된 값을 가져와 각각 `title`과 `body` 상태를 업데이트합니다.

 

 // 추가 
const clickAddBtnHandler = function (event) {

  const newTodo = {
    id: todos.length + 1,
    title,
    body,
    isDone: false,
  };

  // ✨불변성 유지
  setTodos([...todos, newTodo]);

};

 

- `clickAddBtnHandler`는 "추가" 버튼 클릭 이벤트를 처리하는 함수입니다. 새로운 newTodo항목 객체를 생성하고 이를 기존의 `todos` 배열에 추가하기 위해 불변성을 유지하며 새로 리뉴얼?? 된 `setTodos`를 호출합니다.

 

// 삭제
const clickRemoveBtnHandler = (id) => {
  const newTodo = todos.filter(function (todos) {
    return todos.id !== id;
  })
  setTodos(newTodo);
}

 

- `clickRemoveBtnHandler`는 삭제 버튼 클릭 이벤트를 처리하는 함수입니다. 해당 todos 항목의 `id`와 일치하지 않는 항목들로 이루어진 새로운 배열 newTodo를 생성하여 `setTodos`를 호출하여 newTodo를 넣어 `todos` 상태를 업데이트합니다.

 

// 완료 취소
const doneTodoHandler = (id) => {
  const newTodoList = todos.map((todo) => {
    if (todo.id === id) return { ...todo, isDone: !(todo.isDone) };  // todo, todos 확인
    return todo;
  });
  setTodos(newTodoList);
}

 

- `doneTodoHandler`는 완료/취소 버튼 클릭 이벤트를 처리하는 함수입니다. 해당 todos 항목의 `isDone` 값을 토글하여 완료 상태를 변경합니다.

- `map` 함수를 사용하여 모든 todos 항목을 순회하며 해당 항목의 `id`와 일치하는 경우에만 `isDone` 값을 반전시켜 그 todo만으로 만들어진 newTodoList배열을 만듭니다. 변경된 배열을 `setTodos`를 호출하여 newTodoList를 넣어 `todos` 상태를 업데이트합니다.


3. 렌더링:

- JSX를 사용하여 Todo 리스트 애플리케이션의 UI를 구성합니다.

 

<div className="container">
  <div>My Todo List</div>
  <div>React</div>
</div>

 

- "My Todo List"와 "React"라는 텍스트를 포함하는 컨테이너를 렌더링합니다.

 

<div className="add-group">
  <div className="input-group">
    <label className="label">제목</label>

    <input
      value={title}
      onChange={(event) => titleChangeHandler(event)}
      type="text" name="body" className="add-input" />


    <label className="label">내용</label>
    <input
      value={body}
      onChange={bodyChangeHandler}
      type="text" name="body" className="add-input" />
  </div>

  <Button clickAddBtnHandler={clickAddBtnHandler} />
</div>

 

- 입력 그룹은 제목과 내용을 입력하는 필드와 "추가" 버튼으로 구성됩니다. 

- 입력 필드의 값은 각각 `title`과 `body` 상태와 바인딩되어 있습니다. 이벤트 핸들러를 통해 사용자 입력에 따라 상태가 업데이트됩니다.

 

<div className="list-container">

        <h2 className="list-title">ing ✨</h2>
        <div className="list-wrapper">
          {todos.filter((todo) => todo.isDone === false).map((todo) => {
            return (
              <div key={`ing-${todo.id}`} className='todo-container'>

                <h2 className="todo-title">{todo.title}</h2>
                <div>{todo.body}</div>

                <div className="button-set">
                  <button 
                    key={todo.id}
                    todo={todo}
                    className="todo-delete-button button"
                    onClick={()=>clickRemoveBtnHandler(todo.id)}>삭제</button>
                    
                  <button
                    key={todo.id}
                    todo={todo}
                    className="todo-delete-button button"
                    onClick={() => doneTodoHandler(todo.id)}>완료</button>
                    
                </div>
              </div>
            )
          })}
        </div>
      </div>


<div className="list-container">
        
        <h2 className="list-title">Done👌</h2>
        <div className="list-wrapper">
          {todos.filter((todo) => todo.isDone === true).map((todo) => {
              return (
                <div key={`done-${todo.id}`} className='todo-container'>

                  <h2 className="todo-title">{todo.title}</h2>
                  <div>{todo.body}</div>

                  <div className="button-set">
                    <button
                      key={todo.id}
                      todo={todo}
                      className="todo-delete-button button"
                      onClick={()=>clickRemoveBtnHandler(todo.id)}>삭제</button>
                      
                    <button
                      key={todo.id}
                      todo={todo}
                      className="todo-delete-button button"
                      onClick={() => doneTodoHandler(todo.id)}>취소</button>
                      
                  </div>
                </div>
              )
            })}
        </div>
      </div>

 

- "ing"과 "Done"으로 구분된 두 개의 Todo 리스트를 렌더링합니다. `filter` 함수를 사용하여 `todos` 배열을 필터링하여 각 상태에 해당하는 Todo 항목들만 선택합니다.

- 그 후 `map` 함수를 사용하여 선택된 Todo 항목들을 JSX로 변환하여 렌더링합니다.

- 각 Todo 항목은 고유한 `key` 속성을 가져야 하며, `ing-` 또는 `done-` 접두사를 사용하여 각 상태에 따라 구분됩니다.
- Todo 항목 컨테이너는 제목, 내용, 삭제 버튼, 완료/취소 버튼으로 구성됩니다. 삭제 및 완료/취소 버튼은 각각`clickRemoveBtnHandler`와 `doneTodoHandler` 함수를 클릭 이벤트 핸들러로 설정하여 동작합니다.


4. `Button` 컴포넌트:

 

const Button = ({clickAddBtnHandler}) => {
  return <button onClick={clickAddBtnHandler} className="add-button">추가!</button>
}

 

- `Button` 컴포넌트는 `clickAddBtnHandler` 함수를 전달받아 "추가" 버튼을 렌더링합니다. 이 컴포넌트는 애플리케이션의 가독성과 재사용성을 높이기 위해 분리된 컴포넌트입니다.


🖇️ https://hh99-todolist.vercel.app/

 

React App

 

hh99-todolist.vercel.app

 

Comments