๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ–ฅ๏ธ/Frontend

[๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ ] ์ผ์ •๊ด€๋ฆฌ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

by HanaV 2023. 6. 27.
728x90

https://www.yes24.com/Product/Goods/62597469?pid=123487&cosemkid=go15325014723890344&gclid=CjwKCAjwkeqkBhAnEiwA5U-uM-TEoCVlWDSzJA2vBdVWRKQI_NXK8EnAMIKXCLzsxNLJmdQc_gpd8RoCtQYQAvD_BwE 

 

๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ  - YES24

๋ฆฌ์•กํŠธ, ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š๋ƒ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค!๊ธฐ๋ณธ๊ธฐ๋ฅผ ๊ผผ๊ผผํ•˜๊ฒŒ! ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊นŒ์ง€ ๋‹ค์–‘ํ•˜๊ฒŒ ๋ฐฐ์šฐ์ž!๋ฆฌ์•กํŠธ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ๊ฐœ๋…์€ ๋ฌผ๋ก ์ด๊ณ  ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜

www.yes24.com

 

 

์ „์ฒด ์†Œ์Šค ์ฝ”๋“œ๋Š” ํ•˜๋‹จ์— ์žˆ์Šต๋‹ˆ๋‹ค

 

 


์†Œ์Šค์ฝ”๋“œ ์ „์ฒด

App.js

import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
 
const App = () => {
  const [todos, setTodos] = useState([
    {
      id: 1,
      text: '์ผ์ •๊ด€๋ฆฌ ์•ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ',
      checked: true,
    },
    {
      id: 2,
      text: 'news api ์‚ฌ์šฉํ•ด์„œ ๋‰ด์Šค ๋ทฐ์–ด ๋งŒ๋“ค๊ธฐ',
      checked: true,
    },
    {
      id: 3,
      text: '๋ฆฌ์•กํŠธ ํ”ผํ”ผํ‹ฐ ๋งŒ๋“ค๊ธฐ',
      checked: false,
    },
  ]);

  const nextId = useRef(4);
 
  const onInsert = useCallback(
    text => {
      const todo = {
        id: nextId.current,
        text,
        checked: false,
      };
      setTodos(todos.concat(todo));
      nextId.current += 1;
    },
    [todos],
  );

  const onRemove = useCallback(
    id => {
      setTodos(todos.filter(todo => todo.id !== id));
    },
    [todos],
  );

  const onToggle = useCallback(
    id => {
      setTodos(
        todos.map(todo =>
          todo.id === id ? { ...todo, checked: !todo.checked } : todo,
        ),
      );
    },
    [todos],
  );

  return (
    <TodoTemplate>
      <TodoInsert onInsert={onInsert} />
      <TodoList todos={todos} onRemove={onRemove} onToggle={onToggle}/>
    </TodoTemplate>
  );

};
 
export default App;

 

TodoInsert.js

import React, { useState, useCallback } from 'react';
import { MdAdd } from 'react-icons/md';
import './TodoInsert.scss';
 
const TodoInsert = ( {onInsert} ) => {

  const [value, setValue] = useState("");

  const onChange = useCallback(e => {
      setValue(e.target.value);
    }, []);

  const onSubmit = useCallback(
    e => {
      onInsert(value);
      setValue("");
      e.preventDefault();
    },
    [onInsert, value],
  );

  return (
    <form className="TodoInsert" onSubmit={onSubmit}>
    <input
      placeholder="ํ•  ์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”"
      value={value}
      onChange={onChange}
    />
    <button type="submit">
      <MdAdd />
    </button>
  </form>
  );
};
 
export default TodoInsert;

 

TodoInsert.scss

.TodoTemplate {
    width: 512px;
    margin-left: auto;
    margin-right: auto;
    margin-top: 6rem;
    border-radius: 4px;
    overflow: hidden;

    .app-title {
        background: #22b8cf;
        color: white;
        height: 4rem;
        font-size: 1.5rem;
        display: flex; // ์ฃผ๋ชฉ
        align-items: center;
        justify-content: center;
    }
    
    .content {
        background: white;
    }
}

 

TodoList.js

import React from 'react';
import TodoListItem from './TodoListItem';
import './TodoList.scss';

const TodoList = ({ todos, onRemove, onToggle }) => {
  return (
    <div className="TodoList">
      {todos.map(todo => (
        <TodoListItem 
          todo={todo} 
          key={todo.id} 
          onRemove={onRemove}
          onToggle={onToggle}/>
      ))}
    </div>
  );
};

export default TodoList;

 

TodoList.scss

.TodoList {
    min-height: 320px;
    max-height: 513px;
    overflow-y: auto;
  }

 

TodoListItem.js

import React from 'react';
import {
  MdCheckBoxOutlineBlank,
  MdCheckBox,
  MdRemoveCircleOutline,
} from 'react-icons/md';
import cn from 'classnames';
import './TodoListItem.scss';


const TodoListItem = ({ todo, onRemove, onToggle }) => {
  const { id, text, checked } = todo;

  return (
    <div className="TodoListItem">
      <div className={cn('checkbox', { checked })} onClick={() => onToggle(id)}>
        {checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
        <div className="text">{text}</div>
      </div>
      <div className="remove" onClick={() => onRemove(id)}>
        <MdRemoveCircleOutline />
      </div>
    </div>
  );
};

export default TodoListItem;

 

TodoListItem.scss

.TodoListItem {
    padding: 1rem;
    display: flex;
    align-items: center;
    &:nth-child(even) {
      background: #f8f9fa;
    }
    .checkbox {
      cursor: pointer;
      flex: 1;
      display: flex;
      align-items: center;
      svg {
        font-size: 1.5rem;
      }
      .text {
        margin-left: 0.5rem;
        flex: 1;
      }
      &.checked {
        svg {
          color: #22b8cf;
        }
        .text {
          color: #adb5bd;
          text-decoration: line-through;
        }
      }
    }
  .remove {
      display: flex;
      align-items: center;
      font-size: 1.5rem;
      color: #ff6b6b;
      cursor: pointer;
      &:hover {
        color: #ff8787;
      }
    }
    & + & {
      border-top: 1px solid #dee2e6;
    }
  }

 

TodoTemplate.js

import React from 'react';
import './TodoTemplate.scss';

const TodoTemplate = ({ children }) => {
  return (
    <div className="TodoTemplate">
      <div className="app-title">์ผ์ • ๊ด€๋ฆฌ</div>
      <div className="contents">{children}</div>
    </div>
  );
};

export default TodoTemplate;

 

TodoTemplate.scss

.TodoTemplate {
    width: 512px;
    margin-left: auto;
    margin-right: auto;
    margin-top: 6rem;
    border-radius: 4px;
    overflow: hidden;

    .app-title {
        background: #22b8cf;
        color: white;
        height: 4rem;
        font-size: 1.5rem;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    
    .content {
        background: white;
    }
}

 

728x90

"); wcs_do();