어서와, 개발은 처음이지?

4.React Native State와 Props - 2부(Props) 본문

React/React Native

4.React Native State와 Props - 2부(Props)

오지고지리고알파고포켓몬고 2018. 7. 23. 16:00



이 글은 4.React Native State와 Props - 1부(State)와 이어집니다



Props


props는 커스텀 컴포넌트와 관계가 깊습니다.

썩 와닿는 예는 아니지만 이번엔 사용자 별로 버튼을 각각 만든다고 가정해봅니다.

 

거두절미하고 코드부터 보시죠



일단 프로젝트 안에 TestComponent.js라는 파일을 만들고, 아래 코드를 붙여줍니다.

import React, { Component } from 'react';
import {
  View,
  Button,
  Text,
} from 'react-native';

export default class TestComponent extends Component{
  constructor(props){
    super(props);
  }

  render(){
    return(
      <View>
        <Text>{this.props.id}의 버튼</Text>
        <Button
          color={this.props.color}
          title={this.props.title}
          onPress={this.props.updateCount}/>
      </View>
    )
  }
}

그리고 App.js의 코드는 아래와 같이 바꿔줍니다.

import React, {Component} from 'react';
import {StyleSheet, Button, View} from 'react-native';
import TestComponent from './TestComponent';

const datas = [
  {id:"gdHong",count:0,color:"red"},
  {id:"ksYu",count:0,color:"green"},
  {id:"ssLee",count:0,color:"blue"},
];
type Props = {};
export default class App extends Component<Props> {
  constructor(props){
    super(props);
    this.state={datas:datas};
  }

  _updateCount(idx){
    const newDatas = [...this.state.datas];
    newDatas[idx].count = newDatas[idx].count + 1;
    // newArray[idx].count++;

    this.setState({datas:newDatas});
  }

  render() {
    return (
      <View style={styles.container}>
        {
          this.state.datas.map((data, index) => {
            return(
              <TestComponent
                key={data.id}
                id={data.id}
                color={data.color}
                title={data.count.toString()}
                updateCount={this._updateCount.bind(this, index)}/>
            )
          })
        }
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
});

프로젝트를 실행하면 위와 같은 화면을 볼 수 있습니다.

일단 먼저 App.js 코드를 차근차근 짚어보죠.

import React, {Component} from 'react';
import {StyleSheet, Button, View} from 'react-native';
import TestComponent from './TestComponent';

const datas = [
  {id:"gdHong",count:0,color:"red"},
  {id:"ksYu",count:0,color:"green"},
  {id:"ssLee",count:0,color:"blue"},
];
type Props = {};
export default class App extends Component {
  constructor(props){
    super(props);
    this.state={datas:datas};
  }
  .
  .
  .
}

전체적인 맥락은 State의 예제 코드와 비슷합니다.

다만 사용자 별 버튼이 다르게 동작하는 것을 보여주기 위해 datas라는 배열을 초기화 했습니다.


커스텀 컴포넌트는 import TestComponent from './TestComponent'; 식으로 가져와서 사용할 수 있습니다.

'./TestComponent'는 실제 파일 명인 'TestComponent.js'를 뜻합니다.


TestComponent2.js로 이름이 바뀐다면 import TestComponent from './TestComponent2'; 라고 바꿔주시면 됩니다.

render() {
    return (
      <View style={styles.container}>
        {
          this.state.datas.map((data, index) => {
            return(
              <TestComponent
                key={data.id}
                id={data.id}
                color={data.color}
                title={data.count.toString()}
                updateCount={this._updateCount.bind(this, index)}/>
            )
          })
        }
      </View>
    );
  }

커스텀 컴포넌트 역시 Basic Component처럼 JSX 문법으로 사용할 수 있습니다.

map 함수를 사용해서 datas의 각 요소를 사용하여 TestComponent를 생성했으며, 이해하기 쉽게 쓰면 아래와 같습니다.

render() {
    const arr = [];
    for(let i=0; i<this.state.datas.length; i++){
      let component = (
        <TestComponent
          key={this.state.datas[i].id}
          id={this.state.datas[i].id}
          color={this.state.datas[i].color}
          title={this.state.datas[i].count.toString()}
          updateCount={this._updateCount.bind(this, i)} />
      );
      arr.push(component);
    }

    return (
      <View style={styles.container}>
        { arr }
      </View>
    );
  }

그리고 이것은 실제로 아래처럼 동작하게 됩니다

render() {
    return (
      <View style={styles.container}>
        <TestComponent
          key={"gdHong"}
          id={"gdHong"}
          color={"red"}
          title={"0"}
          updateCount={this._updateCount.bind(this, 0)}/>
        <TestComponent
          key={"ksYu"}
          id={"ksYu"}
          color={"green"}
          title={"0"}
          updateCount={this._updateCount.bind(this, 1)}/>
        <TestComponent
          key={"ssLee"}
          id={"ssLee"}
          color={"blue"}
          title={"0"}
          updateCount={this._updateCount.bind(this, 2)}/>
      </View>
    );
  }


다음은 TestComponent입니다.

import React, { Component } from 'react';
import {
  View,
  Button,
  Text,
} from 'react-native';

export default class TestComponent extends Component{
  constructor(props){
    super(props);
  }

  render(){
    return(
      <View>
        <Text>{this.props.id}의 버튼</Text>
        <Button
          color={this.props.color}
          title={this.props.title}
          onPress={this.props.updateCount}/>
      </View>
    )
  }
}

App.js에 비해 아주 간단해보이네요.

render()를 보시면 <Text>에 사용자 id를 나타내고 <Button>의 색과 글자를 입력해줍니다.


자세히보니 여기서 props가 나옵니다.


상위 컴포넌트에서 <TestComponent  id= color= title= updateCount= />라고 넘긴 것들이

하위 컴포넌트에서 props.id props.color props.title props.updateCount라고 쓰여지게 되는 겁니다!


1.버튼을 누르면 

2._updateCount(idx)가 호출되고 

3.idx에 따른 state가 1 증가하게 되고

4.state가 변경됐기때문에 rerender가 일어나고

5.이에따라 props이 변경(props.title이 0 -> 1로 변경)되기 때문에 새로 그려지게 되는 것 입니다.



_updateCount(idx){
    const newDatas = [...this.state.datas];
    newDatas[idx].count = newDatas[idx].count + 1;
    // newArray[idx].count++;

    this.setState({datas:newDatas});
  }

마지막으로 그냥 넘어가면 섭섭한, 함수에 대한 설명입니다.


원리는 간단합니다.

newDatas라는 배열에 State의 datas를 deep copy합니다.

그리고 idx에 해당하는 count를 추가한 뒤, setState()를 통해 새로 업데이트합니다.


idx는 updateCount={this._updateCount.bind(this. index)}에서

bind함수를 통해 index를 전달했습니다.

bind함수는 두번째 인자부터 그대로 함수에 전달됩니다.


updateCount={() => this._updateCount(index)} 처럼 넘겨주는 방법도 있습니다.

함수를 넘겨주는 패턴이 꽤 많아서 나중에 다시 설명하겠습니다.



요약


* 사전지식 - JSX 안에서 javascript 객체(값)를 사용할때는 {}로 감싸서 전달한다.

* props, state가 변경될때마다 render()가 새로 일어난다.

* state에는 현재 화면과 관련된 가변 값을 주로 담는다.

* props에는 상위 컴포넌트에서 전달 받은 값이 들어있다.



마치며


드디어 지겨운 이론공부는 끝이 났습니다.

이제 React Native 앱개발에 필요한 기초 이론은 모두 습득하셨습니다.


다음부터는 UI를 작업과 함께 앱 만들기를 시작해보겠습니다.


Comming Soon!

4 Comments
댓글쓰기 폼