React 컴포넌트(React Component)에 props를 전달할 수 있다.=>
< 전달이름={전달하고픈이야기} >
이벤트 핸들러 함수를 만들고 React에서 이용할 수 있다.=>
확인!
실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 state이고 props에 적합한지 판단할 수 있다.=>
props는 변하지 않고 전달받아야할 데이터에 state는 컴포넌트가 렌더링될때마다 변하는 데이터에!
실제 웹 애플리케이션 개발 시 적합한 state와 props의 위치를 스스로 정할 수 있다.
React의 단방향 데이터 흐름(One-way data flow)에 대해 자신의 언어로 설명할 수 있다.=>
데이터는 상위 컴포넌트에서 하위 컴포넌트로 props를 통해 전달할 수 있다. 하위 컴포넌트의 데이터를 상위 컴포넌트로 전달해주려면 상태 끌어올리기를 사용하자!
외부로 부터 전달받은 값, 변경함수
컴포넌트의 속성
을 의미
부모 컴포넌트(상위 컴포넌트)로 부터 전달
받은 값
외부로부터 전달받은 변하지 않는 값
읽기전용
객체형태
하위 컴포넌트에 전달하고자 하는 값(data)와 속성을 정의한다.
props를 이용하여 정의된 값과 속성을 전달한다.
전달받은 props를 렌더링한다.
위 단계에 맞추어 props를 사용하기 위해 우선 <Parent>
와 <Child>
라는 컴포넌트를 선언하고,
<Parent>
컴포넌트 안에 <Child>
컴포넌트를 작성
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child /> // 응애 나 Child 컴포넌트
</div>
);
};
function Child() {
return (
<div className="child"></div>
);
};
컴포넌트를 만들었으니 이제 전달하고자 하는 속성을 정의하자.
HTML에서 속성과 값을 할당하는 방법과 같음
<a href="www.codestates.com">Click me to visit Code States</a
React 에서 속성 및 값을 할당하는 방법도 이와 유사.
다만, 전달하고자 하는 값을 중괄호 {} 를 이용하여 감싸주기
<Child attribute={value} />
Example 1) Child 컴포넌트에 text속성 선언후 값 할당
<Child text={"I'm the eldest child"} />
이제 <Parent>
컴포넌트에서 전달한 "I'm the eldest child"라는 문자열을 <Child>
컴포넌트에서 받아 보자
함수에 인자를 전달하듯이 React 컴포넌트에 props 를 전달하면 되고
이 props 가 필요한 모든 데이터를 가지고 오게 됨.
function Child(props) {
return (
<div className="child"></div>
);
};
props를 전달 받았으니, 마지막으로 이 props 를 렌더링해보자.
props 를 렌더링하려면 JSX 안에 직접 불러서 사용하면 됨.
다만, props 는 객체라고 하였고
이 객체의 { key : value } 는 <Parent>
컴포넌트에서 정의한 { attribute : value } 의 형태를 띠게 됨.
따라서 JavaScript 에서 객체의 value 에 접근할 때 dot notation 을 사용하는 것과 동일하게
props 의 value 또한 dot notation 으로 접근할 수 있음.
아래와 같이 props.text를 JSX에 중괄호와 함께 작성하자.
function Child(props) {
return (
<div className="child">
<p>{props.text}</p>
</div>
);
};
// props.text 속성만 쏙 가져옴
props 를 전달하는 또 다른 방법으로 여는 태그와 닫는 태그의 사이에 value 를 넣어 전달할 수 있음.
이 경우 props.children 을 이용하면 해당 value 에 접근하여 사용할 수 있음.
단 props.children 쓰면 붙은거 다 가져오는듯?
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child>I'm the eldest child</Child> // 이 사이에 넣은 것들은 다 props.childen으로 가져옴
</div>
);
};
function Child(props) {
return (
<div className="child">
<p>{props.children}</p>
</div>
);
import "./styles.css";
const App = () => {
const itemOne = "React를";
const itemTwo = "배우고 있습니다.";
return (
<div className="App">
<Learn>{itemOne}</Learn> // itemOne을 Learn 컴포넌트로 props해줌
<Learn>{itemTwo}</Learn>
</div>
);
};
const Learn = (props) => {
return <div className="Learn">
{props.children} // props 받음
</div>;
};
export default App;
<Food chicken="KFC" pizza="Dominos" />
자식 컴포넌트에서는 기본적으로 아래와 같은 형태로 액세스하게 됩니다.
const Food = ( foodBrands ) => {
console.log(`좋아하는 치킨은 ${foodBrands.chicken} 입니다.`);
console.log(`좋아하는 피자는 ${foodBrands.pizza} 입니다.`);
};
이를 구조분해 할당을 이용하여 좀 더 직관적이고 가독성 높게 작성할 수 있습니다.
(* 주의할점은 기본적으로 전달하는 props의 키와 동일한 이름을 사용해야 한다는 것입니다.)
const Food = ( {chicken, pizza} ) => {
console.log(`좋아하는 치킨은 ${chicken} 입니다.`);
console.log(`좋아하는 피자는 ${pizza} 입니다.`);
};
컴포넌트 내에서 변할 수 있는 값, 즉 상태는 React state로 다뤄야 함.
state를 다루는 방법중 하나로 useState라는 특별한 함수가 있음.
이를 사용하기 위해선 import {useState} from "react" 써 줘야함.
이후 useState를 컴포넌트 안에서 호출함. like stat 라는 변수를 선언하는 느낌적인 느낌적인 느낌.
일반적인 변수는 함수가 끝날때 사라지지만 state변수는 React에 의해 사라지지 않음.
function CheckboxExample() {
// 새로운 state 변수를 선언하고, 여기서는 이것을 isChecked 라 부르겠습니다.
const [isChecked, setIsChecked] = useState(false);
구조분해할당으로 풀어쓰면
const stateHookArray = useState(false); // 2번
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
수도코드는
const [isChecked, setIsChecked] = useState(false);
// const [state 저장 변수, state 갱신 함수] = useState(state 초기 값);
isChecked : state를 저장하는 변수
setIsChecked : state isChecked 를 변경하는 함수
useState : state hook
false : state 초기값
여기서는 isChecked 가 boolean 값을 가지기 때문에 true or false 여부에 따라 다른 결과가 보이도록 삼항연산자를 사용
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
여기서 <input type에서 checked는 걍 속성임. handleChecked안에 e.target.checked에서 checked는 이벤트 객체안에 이미 포함되어 있는 checked임!
React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용
JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달
예를 들어 HTML에서 이벤트 처리 방식이 아래와 같다면,
<button onclick="handleEvent()">Event</button>
React의 이벤트 처리 방식은 아래와 같습니다. (중괄호 사용 , () 안씀)
<button onClick={handleEvent}>Event</button>
handleEvent() 하면 렌더링 될때 이미 실행되어 버리므로 함수를 전달하는게 아니라 그 결과값만 onClick에 전달해게 됨!
<input>
<textarea>
<select>
와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는데 사용됨
React 에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트함
onChange 이벤트가 발생하면 e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있음.
컴포넌트 return 문 안의 input 태그에 value 와 onChange 를 넣어줌.
이때 onChange 는 input 의 텍스트가 바뀔 때 마다 발생하는 이벤트입니다.
이벤트가 발생하면 handleChange 함수가 작동하며
이벤트 객체에 담긴 input 값을 setState 를 통해 새로운 state 로 갱신합니다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
onClick 이벤트는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트.
버튼이나 <a>
tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때
자주 사용하는 이벤트입니다.
위의 onChange 예시에 버튼을 추가하여 버튼 클릭 시 input tag 에 입력한 이름이 alert을 통해 알림창이 팝업되도록 코드를 추가
// 함수 정의하기
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// 함수 자체를 전달하기
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링될 때 함수 자체가 아닌 함수 호출의 결과가 onClick 에 적용됨.
때문에 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링될 때에 alert 이 실행되고 따라서
그 결과인 undefined (함수는 리턴값이 없을 때 undefined 를 반환합니다.) 가 onClick 에 적용되어
클릭했을 때 아무런 결과도 일어나지 않습니다.
따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 함.
React가 state를 통제할 수 있는 컴포넌트를 Controlled Component라고 함.
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [username, setUsername] = useState("");
const [msg, setMsg] = useState("");
return (
<div className="App">
<div>{username}</div>
<input
type="text"
value={username}
onChange={(event) => setUsername(event.target.value)}
placeholder="여기는 인풋입니다."
className="tweetForm__input--username"
></input>
<div>{msg}</div>
<textarea
placeholder="여기는 텍스트 영역입니다."
className="tweetForm__input--message"
onChange={(e) => {
return setMsg(e.target.value)
}}
value={msg}
></textarea>
</div>
);
}
-> 조그만 컴포넌트를 만들자. -> 그리고 점차 상향식으로 앱을 만들자!
-> 즉 데이터 흐름은 하향식 ( 단방향 데이터 흐름)
부모로부터 props를 통해 전달되지 않으면 state가 아님!
시간이 지나도 변하지 않으면 state가 아님!
컴포넌트 안의 다른 state나 prop를 가지고 계산 가능하다면 states아님!
만약 하나의 상태를 기반으로 두 컴포넌트가 영향을 받는다면 이 때에는 공통 소유 컴포넌트를 찾아 그 곳에 상태를 위치해야 함
즉, 두 개의 자식 컴포넌트가 하나의 상태에 접근하고자 할 때는 두 자식의 공통 부모 컴포넌트에 상태를 위치해야 함