React 의 특장점, 렌더 라이프사이클 및 Hook(5) - Props

ASAC 웹 풀스택
2024. 9. 22. 00:27
목차
  1. Props: 파라미터
  2. [State Lifting]
  3. Single Source of Truth
728x90

Props: 파라미터

값을 부모 컴포넌트가 자식 컴포넌트에게 넘겨줄때 props로 전달

  • 자식 컴포넌트에게 넘겨줄 props값 일반적인 예시
    • 부모 컴포넌트의 State
    • 부모 컴포넌트이 State를 변경할 수 있는 SetState

 

[State Lifting]

State Lifting(상태 끌어올리기): 자식 컴포넌트가 부모 컴포넌트의 State를 SetState로 변경

 

state Liftring을 위해 매번 State, SetState 2개씩 보내주어야할까?

 

SetState 사용법 2가지

  1. SetState(새로운 상태값)
  2. SetState(새로운 상태값 생성 함수)
function ButtonComponent(
/* props → object destructure */ { className, onClick, children },
) {
// const className = props.className
// const onClick = props.onClick
// const children = props.children
return (
<button className={className} onClick={onClick}>
{children}
</button>
)
}
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>{count}</div>
<div>
<ButtonComponent
className='increase-button'
onClick={() => setCount((previousCount) => previousCount + 1)}
>
증가
</ButtonComponent>
<ButtonComponent
// 중괄호 JS 로직으로 string 을 넘길수도 있다.
className={'decrease-button'}
onClick={() => setCount((previousCount) => previousCount - 1)}
>
감소
</ButtonComponent>
</div>
</>
)
}

App 부모 컴포넌트의 state를 변경할 수 있는 setState함수를 ButtonComponent라는 자식 컴포넌트에게 넘겨주는 코드이다.

 

[state Lifting에서 자주하는 실수]

부모-자식 관계에서 Props 파라미터로 넘겨받은 부모 state 값을 자식 state 초기값으로 사용

이렇게 사용할 경우 부모가 props 파라미터로 넘긴값을 변경했을때 자식은 어떠한 변경도 인지하지 못함.

이 문제의 원인은 동일한 1개의 값에 대해 2개의 부모 상태와 자식 상태를 갖기 때문이다.

  • single source of Truth원칙
    • 모든 상태들은 자신을 "소유"하는 특정 컴포넌트가 있어야한다.
    • 아래 코드 실습을 통해 single source of turth원칙과 그것을 의도적으로 쪼갠것을 설명한다.

 

Single Source of Truth

1. single source of truth 원칙 예

import '@/App.css'
import { useState } from 'react'
function ListItem({ name, age, desc, setDesc }) {
const [activated, setActivate] = useState(false) //초기값 false
return (
<li
style={{ textAlign: 'left' }}
onClick={(e) => setActivate((previous) => !previous)} {/* 1. true */} {/* 3. true */}
>
{name} | {age} |{' '}
{activated ? (
<>
<input
value={desc}
onClick={(e) => e.stopPropagation()}
onChange={(e) => setDesc(e.currentTarget.value)}
/>
<button onClick={(e) => setActivate((previous) => !previous)}> {/* 2. flase */}
확인
</button>
<button onClick={(e) => setActivate((previous) => !previous)}>
취소
</button>
</>
) : (
<span>{desc}</span>
)}
</li>
)
}
function UnorderedList({ items, setItems }) {
return (
<ul>
{items.map((item, index) => (
<ListItem
key={index}
name={item.name}
age={item.age}
desc={item.desc}
setDesc={(input) => {
const updated = [...items]
updated[index].desc = input
setItems(updated)
}}
/>
))}
</ul>
)
}
function App() {
const [items, setItems] = useState([
{ name: 'Aaron', age: 10, desc: '안녕하세요' },
{ name: 'Baron', age: 30, desc: '반갑습니다' },
{ name: 'Caron', age: 22, desc: '처음뵙겠습니다' },
{ name: 'Daron', age: 17, desc: '보고싶었습니다' },
])
return (
<>
<div>
{/* ul = Unordered List */}
<UnorderedList items={items} setItems={setItems} />
{/* ol = Ordered List */}
<ol>
{/* li = List Item */}
<li>Ordered List Item 1</li>
<li>Ordered List Item 2</li>
<li>Ordered List Item 3</li>
</ol>
</div>
</>
)
}
export default App

 

문제: 이벤트 버블링에 의해 확인, 취소 버튼을 눌러도 input태그가 사라지지 않음 

  1. 부모<li>  태그 클릭 시 activated 상태 true로 변경
  2. activated ture이므로 input태그 보이고 자식 (input 태그) 에서 다시 확인, 취소 버튼을 누르면 activated 상태 false로 변경
  3. 자식 버튼이 눌려진 다음 바로 동시에 부모<li>태그가 눌려져 다시 activated 상태 ture로 변경

원인: 취소 버튼이 눌려진 다음 바로 동시에 부모<li> 가 눌려져 다시 열림

//1
setActive(!activated)
//2
setActive((pervious) => !previous)

이벤트 버블링 이슈는 첫번째 코드인 경우 발생하지 않지만, 두번째 코드인 경우 발생함

 

setState는 비동기라면서 왜 동기처럼 동작하나?

  • setState는 모두 큐에 쌓여 나중에 수행되기에 비동기로 동작
  • 단, 큐에 쌓인 setState들이 수행될땐 동기로 동작된다.(업데이트 큐에 대한 자세한 설명)
  • CPU는 한번에 하나만 수행 가능하므로...

 

[이벤트 버블링 해결 방법]

StopPropogation으로 자식에서 발생한 이벤트가 부모 이벤트로 전이되는 것을 방지

<button
onClick={(e) => {
e.stopPropagation()
setActivate((previous) => !previous)
}}
>
확인
</button>

 

 

2. single source of truth의 의도적 분리

single source of truth원칙의 기준: 상태 변경의 범주

부모 컴포넌트의 상태와 자식 컴포넌트의 상태를 잘라, 나눠내야할 때

 

이 실습은 의도적으로 부모의 상태와 자식의 상태 변화를 분리하는 경우이다.

일부러 Props로 넘겨준 부모의 state를 그대로 쓰지 않고, 자식 state초기 값으로 사용

 

문제: 취소 버튼을 눌렀지만 변경된 내용이 그대로 반영되는 경우..

원인: 취소 버튼을 눌러도 수정한 내역이 남아 있다.(제대로 콜백되지 않음)

[문제 해결 방법]

취소 버튼 눌렀을 시 setInput(desc) 호출

function ListItem({ name, age, desc, setDesc }) {
const [activated, setActivate] = useState(false)
const [input, setInput] = useState(desc) //입력한 값을 저장하기 위한 중간 저장소를 상태로 만듦
return (
<li
style={{ textAlign: 'left' }}
onClick={(e) => setActivate((previous) => !previous)}
>
{name} | {age} |{' '}
{activated ? (
<>
<input
value={input}
onClick={(e) => e.stopPropagation()}
onChange={(e) => setInput(e.currentTarget.value)} {/input에 입력할때마다 input 상태 변경*/}
/>
<button
onClick={(e) => {
e.stopPropagation()
setActivate((previous) => !previous)
setDesc(input) {/* 확인 버튼을 누르면 input 상태 값을 가지고 desc 상태 값을 변경 */}
}}
>
확인
</button>
<button
onClick={(e) => {
e.stopPropagation()
setActivate((previous) => !previous)
setInput(desc) {/* 부모로부터 받은 decs(수정되기 전)로 input 상태 변경 */}
}}
>
취소
</button>
</>
) : (
<span>{desc}</span>
)}
</li>
)
}

 

728x90

'ASAC 웹 풀스택' 카테고리의 다른 글

React 의 특장점, 렌더 라이프사이클 및 Hook(6) - Ref  (0) 2024.09.22
React 의 특장점, 렌더 라이프사이클 및 Hook(4) - State  (1) 2024.09.22
React: setState에 대해 더 자세히 알아보자  (0) 2024.09.21
React 의 특장점, 렌더 라이프사이클 및 Hook(2) - 단방향 바인딩 + Hook  (1) 2024.09.20
React 의 특장점, 렌더 라이프사이클 및 Hook(1) - JSX문법  (0) 2024.09.20
  1. Props: 파라미터
  2. [State Lifting]
  3. Single Source of Truth
'ASAC 웹 풀스택' 카테고리의 다른 글
  • React 의 특장점, 렌더 라이프사이클 및 Hook(6) - Ref
  • React 의 특장점, 렌더 라이프사이클 및 Hook(4) - State
  • React: setState에 대해 더 자세히 알아보자
  • React 의 특장점, 렌더 라이프사이클 및 Hook(2) - 단방향 바인딩 + Hook
hapBday
hapBday
개발자로 성장하기 위한 기록들hapBday 님의 블로그입니다.
hapBday
개발자로 성장하기 위한 기록들
hapBday
전체
오늘
어제
  • 분류 전체보기 (205)
    • CS (12)
      • 컴퓨터네트워크 (11)
      • 운영체제 (0)
      • 분산 시스템 (0)
      • 데이터베이스 (1)
    • Spring (47)
      • Spring 핵심 원리 (13)
      • Spring MVC (15)
      • Spring DB (12)
      • Spring Security (6)
    • JPA (14)
    • 알고리즘 (30)
      • 프로그래머스 (6)
      • 백준 (20)
    • Design Pattern (0)
    • 언어 (5)
      • JAVA (5)
    • ASAC 웹 풀스택 (38)
      • Spring Boot (21)
      • React (0)
      • DevOps (8)
    • 트러블슈팅 (17)
    • DevOps (5)
      • Docker (5)
    • ETC (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

공지사항

  • 블로그 이전

인기 글

태그

  • basicerrorcontroller
  • Spring
  • Java
  • 백준
  • jwt
  • aws lambda
  • CSRF
  • Session
  • spring boot
  • 오블완
  • multi-stage
  • S3
  • docker workflow
  • docker best practices
  • 구현
  • 김영한
  • 프로그래머스
  • 인프런
  • 3-layerd 아키텍쳐 패턴
  • MVC
  • CORS
  • docker
  • currency control
  • 티스토리챌린지
  • spring security
  • 트랜잭션
  • JPA
  • x-lock
  • s-lock
  • cookie

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.3.0
hapBday
React 의 특장점, 렌더 라이프사이클 및 Hook(5) - Props
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.