๐Ÿง‘‍๐Ÿ’ป ์งง์€ํ˜ธํก/React

[React] ๋‹ค์‹œ ๋งŒ๋“œ๋Š” todo list (ํˆฌ๋‘๋ฉ”์ดํŠธ ํด๋ก ) (1)

ํ•œ๊ทœ์ง„ 2022. 10. 6. 22:49

๋งŒ๋“ค์–ด๋‘” ๊ณผ์ œ ์ปค๋ฆฌํ˜๋Ÿผ์„ ์ฐฌ์ฐฌํžˆ ๋‹ค์‹œ ๋ณด๋‹ค๊ฐ€. ์–ด๋ผ ์ด๊ฑฐ ํˆฌ๋‘๋ฉ”์ดํŠธ ์•„๋‹Œ๊ฐ€?

ํ•ด์„œ GDSC ์Šคํ„ฐ๋”” ๊ธฐ๊ฐ„ ๋™์•ˆ ํˆฌ๋‘๋ฉ”์ดํŠธ ํด๋ก ์ฝ”๋”ฉ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•ด๋ณด๊ธฐ๋กœ.

 

์ขŒ : ํด๋ก  / ์šฐ : ํˆฌ๋‘๋ฉ”์ดํŠธ

ํด๋ก ์ฝ”๋”ฉ์ธ ๋งŒํผ ์ตœ๋Œ€ํ•œ ๋˜‘๊ฐ™์ด ์Šคํƒ€์ผ์„ ๋„ฃ์œผ๋ ค ๋…ธ๋ ฅํ–ˆ๋‹ค. ๊ฐ–๊ณ  ์žˆ๋Š” ์‚ฐ์„ธ๋ฆฌํ”„ ๊ธ€๊ผด์„ ๋ช‡๊ฐœ ๋„ฃ์–ด๋ดค๋Š”๋ฐ, ํ”„๋ฆฌํ…๋‹ค๋“œ์˜€๋‹ค. ์ข‹์•„ํ•˜๋Š” ํฐํŠธ์•ผ. ๊ทธ ์™ธ์— ์ด๋ฏธ์ง€๋‚˜ ์•„์ด์ฝ˜ ๋“ฑ์€ ๊ฐœ๋ฐœ์ž๋„๊ตฌ ๋„คํŠธ์›Œํฌํƒญ์—์„œ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ํ”ผ๊ทธ๋งˆ์—์„œ ์ง์ ‘ ๋งŒ๋“ค์–ด svg๋กœ ๋‚ด๋ณด๋‚ด ์‚ฌ์šฉํ–ˆ๋‹ค.

 

 


 

 

์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ์— ์•ž์„œ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์งค์ง€์— ๋Œ€ํ•ด์„œ ๊ณ ๋ฏผ์„ ๊ฝค ์˜ค๋ž˜ ํ–ˆ์—ˆ๋‹ค. ์‹ค์ œ ํˆฌ๋‘๋ฉ”์ดํŠธ๋ฅผ ๋ณด๋ฉด ๋“œ๋ž˜๊ทธ์•ค ๋“œ๋ž์œผ๋กœ ํˆฌ๋‘๋ฅผ ์˜ฎ๊ฒจ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ์žˆ๋‹ค. ์‹ฌ์ง€์–ด ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ๋„!

ํ•˜์ง€๋งŒ - ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํˆฌ๋‘- -์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํˆฌ๋‘- ์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌํ•ด๋†“์œผ๋ฉด ๋‚˜์ค‘์— ๋“œ๋ž˜๊ทธ์•ค๋“œ๋ž์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ์ด๋™์ด ์•ˆ๋  ๊ฒƒ ๊ฐ™์•˜๋‹ค. ํ†ต์œผ๋กœ ๋ฐฐ์—ด๋กœ ์‚ฌ์šฉํ•ด์•ผํ•˜๋‚˜ ์‹ถ์—ˆ์ง€๋งŒ... ์‹œ๊ฐ„์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋‹จ์€ ๋– ์˜ค๋ฅด๋Š” ๋Œ€๋กœ ๊ฐ€์žฅ ์ง๊ด€์ ์ธ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

const Feed = () => {
  const categories = useRecoilValue(categoryState);

  return (
    <Wrapper>
      <div>Feed</div>
      <List>
        {categories.map((category) => (
          <FeedItemList category={category} key={category.label} />
        ))}
      </List>
    </Wrapper>
  );
};

export default Feed;

์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋ฐฐ์—ด์„ ๊ฐ–๊ณ  ์™€์„œ ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋งˆ๋‹ค์˜ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ map์œผ๋กœ ๋ณด์—ฌ์ฃผ๋„๋ก ํ–ˆ๋‹ค.

 

const FeedItemList = ({ category }: { category: ICategory }) => {
  const items = useRecoilValue(todoSelector(category.label));
  const [open, setOpen] = useState<boolean>(false);
  return (
    <>
      <CategoryButton category={category} setOpen={setOpen} />
      {items.map((item) => (
        <TodoItem item={item} key={item.id} />
      ))}
      {open && <InputForm category={category} setOpen={setOpen} />}
    </>
  );
};

export default FeedItemList;

๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ”ผ๋“œ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ์•ˆ์— ์†ํ•˜๋Š” ํˆฌ๋‘ ๋ชฉ๋ก๋“ค์„ ๊ฐ€์ง€๊ณ  ์˜จ๋‹ค. recoil์˜ selector๋ฅผ ์ฒ˜์Œ ์จ๋ณด์•˜๋‹ค.

 

recoil selector

export const todoSelector = selectorFamily<ITodoItem[], string>({
  key: 'todoSelector',
  get:
    (categoryName: string) =>
    ({ get }) =>
      get(todoState).filter((todo) => todo.category.label === categoryName),
});

selector๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜์ด๋‹ค. getํ•จ์ˆ˜์—์„œ๋Š” RecoilValueReadOnly ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ณ  ํ•จ. ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋” ๊ฐ์‹ธ์„œ ์ธ์ž๋ฅผ ๋„˜๊ฒจ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์„ ๋ฐ›์•„์™€์„œ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ํˆฌ๋‘๋งŒ filter๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

 

๊ตฌํ˜„ํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์ด๋ฒˆ์ฃผ ๊ณผ์ œ๋Š” ์ €๋ฒˆ ์ฃผ์— ๋ฐ”๋‹๋ผ JS๋กœ ๋งŒ๋“ค์—ˆ๋˜ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฆฌ์•กํŠธ๋ฅผ ์ด์šฉํ•ด ๋งŒ๋“ค์–ด๋ณด๋Š” ๊ณผ์ œ์˜€๋‹ค. ํˆฌ๋‘๋ฉ”์ดํŠธ์—์„œ ํˆฌ๋‘๋ฅผ ์ฒดํฌํ•˜๋Š” ๋ถ€๋ถ„, ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ Feed ๋ถ€๋ถ„๋งŒ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค. ๋ช‡์‹œ๊ฐ„ ๋‚ด์— ๋‚ด์•ผํ•ด์„œ ๋‚ ๋ฆผ์œผ๋กœ ์ง  ์ฝ”๋“œ๋ผ ๋Œ€๋Œ€์ ์ธ ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•˜๋‹ค. ํŠนํžˆ ์ƒํƒœ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ƒ๊ฐํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

ํˆฌ๋‘ ์ƒ์„ฑํ•˜๊ธฐ

 

 

ํˆฌ๋‘ ์ฒดํฌํ•˜๊ธฐ ํ† ๊ธ€

 

 

ํˆฌ๋‘ ์‚ญ์ œํ•˜๊ธฐ

๋ฑ…ํ‚ค์ฆˆ์—์„œ ์ผ๋˜ react-spring-bottom-sheet ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ฐ”ํ…€์‹œํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งค ํˆฌ๋‘์•„์ดํ…œ ์ปดํฌ๋„ŒํŠธ์— ๋“ค์–ด๊ฐ€๋Š”๋ฐ, ํˆฌ๋‘์•„์ดํ…œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ญ์ œ๋˜๋ฉด์„œ ๋ฐ”ํ…€์‹œํŠธ๊ฐ€ ํ•œ๋ฒˆ์— ๋š ์‚ฌ๋ผ์ง€๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Œ. ๋ฐ”ํ…€์‹œํŠธ๋ฅผ ๋” ์ƒ์œ„์— ์ „์—ญ์œผ๋กœ ๋‘๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์€๋ฐ, ๊ทธ๋Ÿผ ์ƒํƒœ๊ด€๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋œฏ์–ด๊ณ ์ณ์•ผํ•  ๊ฒƒ ๊ฐ™์•„์„œ.. ์ผ๋‹จ ๋ฐ˜์ฐฝ๊ณ ๋งŒ ๋ถ™์—ฌ๋†จ๋‹ค.

 

  const handleDeleteTodo = () => {
    onDismiss();
    setTimeout(() => onDeleteTodo(), 300);
  };

๋ฐ”ํ…€์‹œํŠธ๊ฐ€ ์™„์ „ํžˆ ๋‚ด๋ ค๊ฐ„ ๋‹ค์Œ์— ํˆฌ๋‘๊ฐ€ ์‚ฌ๋ผ์ง€๋„๋ก ํ–ˆ๋‹ค.

 

 


 

 

์ปค๋ฆฌํ˜๋Ÿผ๋งˆ๋‹ค ์˜๋„ํ•˜๋Š” ๋‚ด์šฉ์ด ์žˆ๊ณ  ๊ฐ ๊ณผ์ œ์—์„œ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธฐ์ˆ ๋“ค์ด ์žˆ์ง€๋งŒ ๊ตฌํ˜„์— ๊ธ‰๊ธ‰ํ•ด์„œ ํ•˜๋˜๋Œ€๋กœ ์ต์ˆ™ํ•œ ์Šคํƒ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ŒŒ๋‹ค. '์ฒ˜์Œ์—” state์™€ props๋งŒ์„ ์ด์šฉํ•ด์„œ ๊ด€๋ฆฌํ•˜๋‹ค๊ฐ€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์ƒํƒœ๊ด€๋ฆฌํ•˜๋Š” ๊ณผ์ •'์„ ๊ธฐ๋กํ•˜๊ณ  ๋ฉค๋ฒ„๋“ค๊ณผ๋„ ๊ณต์œ ํ•˜๋Š”๊ฒŒ ์›๋ž˜ ๋ชฉํ‘œ์˜€๋Š”๋ฐ, ์•„์‰ฝ๋‹ค.

 

๋ฐฐํฌ ๋งํฌ

[Week2] ๋ฆฌ์•กํŠธ ์‹œ์ž‘ํ•˜๊ธฐ