Front-end Developer

0%

React Props, State

what is React?

  • 사용자 인터페이스를 구축하기 위한 선언적이고 효율적이며 유연한 JavaScript 라이브러리
  • 컴포넌트라고 불리는 작고 고립된 코드의 파편을 이용하여 복잡한 UI를 구성한다.
    이 컴포넌트를 사용하여 React에게 화면에 표현하고 싶은 것이 무엇인지 알려줌.
  • render함수: 화면에서 보고자 하는 내용을 반환. 컴포넌트가 props라는 매개변수를 받아오면 render 함수를 통해 표시할 뷰 계층 구조를 반환한다.
    React 엘리먼트는 JavaScript 객체이며 변수에 저장하거나 프로그램 여기저기에 전달할 수 있다.

props

부모 컴포넌트에서 자식 컴포넌트로 props를 전달하면 React 앱에서 부모에서 자식으로 정보가 어떻게 흘러가는지 알려준다. 자식 컴포넌트에서 클릭 이벤트 발생에 대한 변화가 필요한데, state는 부모 컴포넌트에 있다면 자식은 부모의 state를 직접 변경할 수 없다. 컴포넌트는 자신이 정의한 state에만 접근할 수 있기 때문이다. 따라서 부모 컴포넌트가 자식 컴포넌트에게 props를 전달하고, 자식 컴포넌트에서는 함수를 호출한다. 아래의 경우 square를 클릭하면 부모 컴포넌트인 Board에서 넘겨받은 함수가 호출된다. 참고로 React에서 이벤트를 나타내는 prop에는 on[Event], 이벤트를 처리하는 함수에는 handle[Event]를 사용하는 것이 일반적이다.

이렇게 부모 컴포넌트가 자식 컴포넌트로 props를 전달하면 부모 컴포넌트에게 값을 받아 클릭 이벤트와 같은 변화가 생길 때 부모 컴포넌트에게 정보를 전달한다. 이런 경우 자식 컴포넌트를 제어되는 컴포넌트라고 한다. 부모 컴포넌트에 의해 제어되기 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//class component
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => this.props.onClick()}>
{this.props.value}
</button>
);
}
}

// function component
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}

state

무엇인가를 기억하기 위해 사용. class 컴포넌트에서는 this.state를 설정하는 것으로 state를 가진다. 주의할 것은 하위 클래스의 생성자를 정의할 때 반드시 super를 호출해야한다. 아래와 같이 작성시 Square의 render 함수 내부에서 onClick 핸들러를 통해 this.setState를 호출하는 것으로 React에게 <button>을 클릭할 때 Square를 다시 렌더링해야 한다고 알릴 수 있다. 업데이트 이후에 Square의 this.state.value는 ‘X’가 되어 게임 판에서 X가 나타나는 것을 확인할 수 있다. 어떤 Square를 클릭하던 X가 나타날 것이다. 컴포넌트에서 setState를 호출하면 React는 자동으로 컴포넌트 내부의 자식 컴포넌트 역시 업데이트한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}

render() {
return (
<button className="square" onClick={() => this.setState({ value: "X" })}>
{this.state.value}
</button>
);
}
}

특정값을 유지해야 할 필요가 있을 때 부모 컴포넌트에 상태를 저장하고, 부모 컴포넌트가 자식 컴포넌트에게 props를 전달하는 것으로 무엇을 표시해야 할지 알려줄 수 있다. 여러개의 자식으로부터 데이터를 모으거나 두 개의 자식 컴포넌트들이 서로 통신하게 하려면 부모 컴포넌트에 공유 state를 정의해야 한다. 부모 컴포넌트는 props를 사용하여 자식 컴포넌트에 state를 다시 전달할 수 있다. 이것은 자식 컴포넌트들이 서로 또는 부모 컴포넌트와 동기화 하도록 만든다. 아래의 경우 부모 컴포넌트인 Board에 생성자를 추가하고, 값을 유지해야하는 squares의 null 배열을 초기 state로 설정했다.

1
2
3
4
5
6
7
8
9
10
11
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}

renderSquare(i) {
return <Square value={i} />;
}

array.fill
arr.fill(value[, start[, end]])

  • value: 배열을 채울 값, start: 시작 인덱스, 기본값 0, end:끝 인덱스, 기본값 this.length
  • arr.fill 메서드는 변경자 메서드로, 복사본이 아니라 this 객체를 변형해 반환.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}

// Objects by reference.
var arr = Array(3).fill({}); // [{}, {}, {}]
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

key 선택

이런 경고가 있다면,

경고 배열이나 이터레이터의 자식들은 고유의 “key” prop을 가지고 있어야 합니다. “Game”의 render 함수를 확인해주세요.

리스트를 렌더링할 때 React는 렌더링하는 리스트 아이템에 대한 정보를 저장한다. 리스트를 업데이트 할 때 React는 무엇이 변했는 지 결정해야 한다.
리스트의 아이템들은 추가, 제거, 재배열, 업데이트 될 수 있다. React는 컴퓨터 프로그램이며 사람이 의도한 바가 무엇인지 알지 못한다.
그렇기 때문에 리스트 아이템에 key prop을 지정하여 각 아이템이 다른 아이템들과 다르다는 것을 알려주어야 한다.

<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>

목록을 다시 렌더링하면 React는 각 리스트 아이템의 키를 가져가며 이전 리스트 아이템에서 일치하는 키를 탐색한다.
현재 리스트에서 이전에 존재하지 않는 키를 가지고 있다면 React는 새로운 컴포넌트를 생성한다.
현재 리스트가 이전 리스트에 존재했던 키를 가지고 있지 않다면 React는 그 키를 가진 컴포넌트를 제거한다.
만약 두 키가 일치한다면 해당 구성요소는 이동한다. 키는 각 컴포넌트를 구별할 수 있도록 하여 React에게 다시 렌더링할 때 state를 유지할 수 있게 한다.
만약 컴포넌트의 키가 변한다면 컴포넌트는 제거되고 새로운 state와 함께 다시 생성된다.동적인 리스트를 만들 때마다 적절한 키를 할당하는 것이 강력하게 추천된다.


Reference
React
MDN