- props
- 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값
- 컴포넌트 자신은 해당 props를 읽기전용으로만 사용 가능
- props의 값을 바꾸려면 부모컴포넌트에서 바꾸어야 한다
- state
- 컴포넌트 내부에서 바뀔 수 있는 값
- 동적 데이터를 다룰 때 사용
- 종류
- 클래스형 컴포넌트의 state
- 함수형 컴포넌트에서 useState 함수를 통해 사용하는 state
클래스형 컴포넌트의 state
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { number: 0 };
}
render() {
const { number } = this.state;
return (
<div>
<h1>{number}</h1>
<button
onClick={() => {
this.setState({ number: number + 1 });
}}
>+1</button>
</div>
);
}
}
export default Counter;
- 컴포넌트에 state를 설정할때, constructor 메서드를 이용
- 컴포넌트의 state는 객체형식이어야 한다
- render함수에서 현재 state를 조회할 때는 this.state을 조회
setState에 함수인자 전달
<button
onClick={() => {
this.setState({ number: number + 1 });
this.setState({ number: this.state.number + 1 });
}}
>
- this.setState는 값을 업데이트할 때 상태가 비동기적으로 업데이트
- setState를 두번 호출했지만 숫자는 1만 늘어난다.
- 값이 비동기적으로 변하기때문에, 바로 바뀌지 않기 때문
<button
onClick={() => {
this.setState((prevState) => {
return {
number: prevState.number + 1,
};
});
this.setState((prevState) => ({
number: prevState.number + 1 //함수에서 바로 객체를 반환한다는 의미
}));
}}
>
- setState에 객체 대신 함수인자를 전달
- 함수에서 객체를 바로 반환하기 때문에, 숫자 2씩 증가
setState 후 특정 작업 수행
<button
onClick={() => {
this.setState(
{
number: number + 1,
},
() => {
console.log('setState 호출됨');
console.log(this.state);
}
);
}}
>
- setState의 두번째 파라미터로 콜백함수 등록
- setState의 작업이 끝난 후, 해당 콜백함수 수행
함수형 컴포넌트의 state
- 리액트 16.8 이전까지는 함수형 컴포넌트에서 state 사용 불가
- 이 후 부터는 useState 함수를 이용해 state 사용
import React, { useState } from 'react';
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('안녕하세요');
const onClickLeave = () => setMessage('안녕히 가세요');
return (
<div>
<button onClick={onClickEnter}>입장</button>
<button onClick={onClickLeave}>퇴장</button>
<h1>{message}</h1>
</div>
);
};
export default Say;
- useState 함수의 인자에는 상태의 초기값을 넣어준다
- 클래스형 컴포넌트에서의 state 초기값 : 객체
- 함수형 컴포넌트에서는 객체가 아니어도 상관없다
- 함수를 호출하면 배열 반환
- 첫번째 원소 : 현재 상태
- 두번째 원소 : 상태를 바꾸어주는 함수 (setter 함수)
- 배열 비구조화 할당을 통해 이름을 자유롭게 정할 수 있다
- const[message,setMessage] = useState(‘’)
- state 사용 이유
- 변수가 변경될 때 자동으로 관련 HTML을 재렌더링하려면, 일반 변수 대신 state에 저장해 데이터바인딩
- 리액트는 state가 변경되면 state가 포함된 HTML을 자동으로 재렌더링
- 일반 변수는 병경이 발생해도 자동으로 재렌더링 해주지 않는다
주의사항
- state의 값을 바꿀 때는 setState나 useState를 통해 전달받은 세터함수 사용
//잘못된예 - 클래스형 컴포넌트
this.state.number = this.state.number+1;
this.state.array = this.array.push(2);
//잘못된예 - 함수형 컴포넌트
const[object, setObject] = useState({a:1, b:1});
object.b=2;
배열이나 객체의 업데이트
- 배열이나 객체의 사본을 만든다
- 사본의 값을 업데이트한다
- 사본의 상태를 세터함수를 통해 업데이트 한다
//객체 다루기
const object = { a:1, b:2, c:3 };
const nextObject = {...object, b:3}; //사본 만든 후 b값만 덮어씀
//배열 다루기
const array = [
{id: 1, value:true},
{id: 2, value:true},
{id: 3, value:false}
];
let nextArray = array.concat({id:4}); // 새 항목 추가
nextArray.filter(item => item.id != = 2); // id가 2인 항목 제거
nextArray.map(item => (item.id === 1 ? {...item,value:false) : item)); // id가 1인 항목의 value를 false로 설정
자식 컴포넌트에서 부모 state 이용
- 자신의 스테이트처럼 접근할 수 없음
- props를 이용해 부모 컴포넌트에서 state를 전달
- 자식컴포넌트에서 {props.state 이름} 으로 접근
잘못된 예
function App (){
let [title, setTitle] = useState(['react 책 추천', '점심메뉴추천', 'node.js스터디']);
return (
<div>
<Detail/>
</div>
)
}
function Detail(){
return (
<div>
<h2>제목 { title[0] }</h2>
<p>작성자</p>
<p>내용</p>
</div>
)
}
//title 변수가 정의되지 않았다고 에러
props 이용
import logo from "./logo.svg";
import "./App.css";
import React, { useState } from 'react';
import Detail from './components/Detail';
const App = () => {
let [title, setTitle] = useState(['react 책 추천', '점심메뉴추천', 'node.js스터디']);
return (
<div>
<Detail title={title} />
</div>
)
};
export default App;
function Detail(props){
return (
<div>
<h2>제목 { props.title[0] }</h2>
<p>작성자</p>
<p>내용</p>
</div>
)
}