State lifting up? 상태 끌어올리기를 말한다.
▶ 리액트에서는 부모 컴포넌트가 자식 컴포넌트의 상태를 직접 변경 할 수 없다
따라서, 자식에서 발생한 이벤트를 부모에서 처리하도록 하는 상태 끌어올리기 패턴을 이용해야한다.
해당 예제 파일에서는 컴포넌트 총 3개를 만들거다!!
1) Id 컴포넌트 (자식)
2) Pw 컴포넌트 (자식)
3) Exam3 컴포넌트 (부모) - 해당 파일에서 내보낼 기본 컴포넌트
이렇게!!!
여기서 잠깐 !
function Id(){
}
함수형 컴포넌트는 이렇게도 사용이 가능!
const Id= () => {
}
💡 JSX 를 사용한 html작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야한다.
<h1></h1>
이렇게 하나만은 사용가능하지만
<h1></h1>
<h1></h1>
인 경우 형제 요소로 되어 이를 모두 감싸는 최상위 태그가 꼭 필요하다!
예를 들면 이렇게?!
<>
<h1></h1>
<h1></h1>
</>
그렇다면 상태 끌어올리기 방법을 코드로 살펴보자 👩💻
import { useState } from "react";
//Id 컴포넌트 (자식)
// ()안에 props를 작성 -> 부모에게서 전달받은 속성을 props라고 부르는데 값을 받을 준비가 되어야하기에 작성필요!
// 매개변수 이름이 props이고 props : {onChangeId} 인 것임.
const Id = (props) => {
const { onChangeId } = props; // props 안에 있는 onChangeId라는 이름의 함수를 이용할 수 있게 됨.
// const [id, setId] = useState(""); // 상태(state) 중 'id'를 생성하고 초기값으로 ""을 설정
return (
// JSX를 사용한 html구문 작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야 한다!
<>
<div>
<label>ID :</label>
<input onChange={onChangeId} />
{/* onChange 이벤트 핸들러에 onChangeId를 연결함 */}
</div>
</>
);
};
//Pw 컴포넌트 (자식)
const Pw = ({ onChangePw }) => {
// {}를 이용하여 props 안에 있는 값을 바로 꺼내서 쓸 수도 있다.
// const [pw, setPw] = useState(""); // 상태(state) 중 'pw'를 생성하고 초기값으로 ""을 설정
return (
// JSX를 사용한 html구문 작성부는 무조건 최상위 부모태그 하나로 감싸져 있어야 한다!
<>
<div>
<label>Pw :</label>
<input onChange={onChangePw} />
</div>
</>
);
};
// Exam3컴포넌트 (부모)
const Exam3 = () => {
// 자식의 상태를 부모에서 정의(상태 끌어올리기)
const [id, setId] = useState("");
const [pw, setPw] = useState("");
// 자식의 상태를 변경할 수 있는 함수를 정의
////id 변경하는 함수 -> 여기서 e는 input창에 작성하는 값을 e라고 지정
const onChangeId = (e) => {
//input창에 입력되는 값을 id로 변경해줄 것임
setId(e.target.value);
};
// input창에 입력되는 값을 pw로 변경해줄 것임
const onChangePw = (e) => {
setPw(e.target.value);
};
return (
<>
{/* 컴포넌트 중 Id를 불러 렌더링 함 (Id가 Exam3의 자식이 됨)
자식 컴포넌트에는 (props)에는 전달만 가능하고 직접 넣는것은 어려움*/}
<Id onChangeId={onChangeId} />
{/* 컴포넌트 중 Pw를 불러 렌더링 함 (Pw가 Exam3의 자식이 됨) */}
<Pw onChangePw={onChangePw} />
<div>
{/* button 의 disabled 속성 : 비활성화 속성 (비활성 true / 활성 false)
-> id 와 pw 둘 다 작성되어야 활성화
*/}
{/* 현재 이렇게만 작성하면 id, pw를 인식하지 못하여 위 상단에 상태를 끌어올리기를 해야한다.
상태 끌어올린 후 이벤트 핸들러도 끌어올려줘야함
id, pw에 input창을 넣어놨는데 리액트에서 상태를 인지할 수 있는 이벤트 핸들러를 만들어놔야한다.*/}
<button disabled={id.length === 0 || pw.length === 0}>Login</button>
</div>
</>
);
};
export default Exam3;

비활성화 되었던 button이 입력 후 활성화 되는것을 볼 수 있음.

Props Drilling이란? 상태 내리 꽂기를 말한다!
▶ props를 통해 데이터를 전달할 때, 자식 컴포넌트에서 필요하지 않은 props를 계속해서 전달하는 행위
따라서 이러한 문제점으로 코드의 가독성 및 유지보수성을 떨어뜨린다...!
Exam4 에서는 Child1 컴포넌트만 부를 것임, Child1 에서는 Child2 컴포넌트만 부르고, Child2 에서는 Child3 컴포넌트만 부르고, Child3 에서는 MyComponent 이런식으로 부를 것이다.
※ 이처럼 부모자식 관계가 연결되어 있을 때!!
Exam4의 상태값을 MyComponent에서 사용해야한다면? 어떻게 해야할까?
import { useState } from "react";
// 부모 컴포넌트
function Exam4() {
const [name, setName] = useState("홍길동");
//클릭되면 네임 상태값 이름을 바꿀것이라는 함수
const handleClick = () => {
setName("손오공");
};
return (
<>
{/* Child1이라는 자식 컴포넌트 불러오고 전달할 값 넣기 여기서 name은 props!*/}
<Child1 name={name} />
<button onClick={handleClick}>이름변경</button>
</>
);
}
// 자식 컴포넌트 Child1
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child1(props) {
// Child2에 props안에 있는 name을 전달한다는 뜻!
return <Child2 name={props.name} />;
}
// 자식 컴포넌트 Child2
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child2(props) {
// Child2에 props안에 있는 name을 전달한다는 뜻!
return <Child3 name={props.name} />;
}
// 자식 컴포넌트 Child3
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function Child3(props) {
// Child3에 props안에 있는 name을 전달한다는 뜻!
return <MyComponent name={props.name} />;
}
// 자식 컴포넌트 MyComponent
//위에서 전달받은 props가 있기에 props를 작성해주면 된다.
function MyComponent(props) {
//props는 Exam4에서 부터 내리꽂기를 통해 전달받은 부모의 상태값
return <h1>{props.name}</h1>;
}
export default Exam4;

이렇게 변경이 된다

: 객체 내부의 모든 값을 props로 전달하는 방법
import { useState } from "react";
// 부모
function Exam5() {
// userState() 여기 상태값에 배열, 자바스크립트 객체 값도 전달 가능함!
const [userData, setUserData] = useState({ name: "홍길동", age: 30 });
//...userData는 name ={userData.name} age={userData.age}로 상태값을 전달하는 것과 같음
return <MyComponent {...userData} />;
}
//자식
function MyComponent(props) {
const { name, age } = props;
const content = `안녕하세요 제 이름은 ${name} 이고, 나이는 ${age}세 입니다`;
return <h3>{content}</h3>;
}
export default Exam5;
결과
