React

[REACT] React - props, state, import

Hwan'ss 2019. 8. 2. 15:18

2019.08.02(금)

React - props, state, import

 

1. props vs state

- props는 값을 갱신 할 수 없으며, state는 값을 갱신 할 수 있다.

- props는 값을 상위 컴포넌트가 전달 하는 것이지만, state는 컴포넌트 자체에서 초기화하는 것이다.

- state는 값을 갱신 할 수 있지만 setState() 함수를 사용해서 값을 갱신 할 수 있다.

- setState() 함수의 갱신 형식은 객체의 구조를 따르고 있다.

- setState() 함수는 비동기 함수이다. 예제를 보면 알겠지만 버튼1을 클릭했을 때 콘솔의 값을 보면 1이어야 되는데 0이 출력된다. setState() 함수는 비동기 함수이기 때문에 언제 값이 변경 될지는 모르지만 render() 함수가 호출 되기 전에는 값이 변경된다. 즉, 다음 render() 함수가 호출되기 전에는 비동기가 풀린다는 말이다. 그렇기 때문에 제어문을 사용 할 때 주의해야 된다. (변경되는 시점을 알고 제어문을 사용해야 한다.)

 

2. state 변수와 필드 변수

- state 변수는 render()를 call 하지만, 일반 필드 변수는 render() 함수를 call 하지 않는다.

- state 변수는 컴포넌트안의 값을 갱신하는 용도로 사용하는 변수이다. 즉, 웹 페이지를 통해 보이는 변수는 모두 state 변수를 사용한다.

- 화면에 보이는 것과 상관없이 console이나 디버깅 체크를 위해 사용되는 변수들은 일반 필드 변수를 사용하면 된다.

 

...더보기

* 참고

props와 state의 차이를 알아야 되며 특히 state에 대해 잘 알고 있어야 뒷부분에서 문제가 발생하지 않는다.

 

3. 실습

  • Ex01(props)
// App.js

import React, { Component, Fragment } from 'react';
import Bpp from './apple/bpp.js'

class App extends Component {
  render() {
    return (
      <Fragment>
        {/* ''안의 숫자는 String, {} 안에 숫자를 넣어야 Number */}
        <Bpp n1='나는야문자열' n2='100' n3={200}></Bpp>
      </Fragment>
    );
  }
}

export default App;
// bpp.js

import React, { Component, Fragment } from 'react';

class bpp extends Component {
    render() {
        console.log(this.props.n1);
        
        // 이론상 문제가 없는데 에러가 발생한다.
        // 여기서 props는 데이터를 갱신 할 수 없다.
        // 여기 안에서 갱신이 불가능 하다는 거지 props의 값을 변경 할 수 없다는 뜻이 아니다.
        // 부모가 어떤식으로든 재 갱신 할 수 있는 값을 던질수 있다.
        // 부모가 값을 변경할 수 있다는 말이다. 자식에서는 값을 변경 할 수가 없다.
        
        //this.props.n3 = 50
        
        return (
            <Fragment>
                <h2>난 비피피</h2>
                 <h3>{ this.props.n1 } { this.props.n2 } { this.props.n3 }</h3>
            </Fragment>
        );
    }
}

export default bpp;

Ex01 실행결과

  • Ex02 (state와 필드변수)
import React, { Component } from 'react';

class App extends Component {
  // 객체 state
  // state를 이용해서 변수 사용
  // state는 값을 변경 할 수 있다.
  // state 초기화
  state = {  
    n1 : 0,  
  }

  // class이기 때문에 필드 변수도 선언이 가능하다.
  n2 = 0;

  f1 = () => {
    // 값을 갱신 시킬 수 있는데 단독으로 갱신 시킬 수 없다.
    // 형식을 갖추어서 갱신을 시켜야 한다. setState() 사용
    // this.state.n1++  이렇게 갱신 불가
    // 객체를 갱신하는 것이기 때문에 { } 사용해야 한다.
    // setState는 한 줄 처리 하지 않는다.
    // state는 render()을 호출한다.
    this.setState({ 
      n1:this.state.n1+1 
    });
    console.log(this.state.n1);
  }

  f2 = () => {
    this.n2++;
    console.log(this.n2);
  }

  
  render() {
    console.log('g');
    return (
      <div>
        <h1>{ this.state.n1 }</h1>
        <button onClick={this.f1}>버튼1</button>
        <h1>{this.n2}</h1>
        <button onClick={this.f2}>버튼2</button>
        {/* 필드인 n2를 사용하면 바로 값 갱신이 가능한데 왜 state를 사용하는가... */}
        {/* state는 render()함수를 호출하기 때문에 웹페이지에서 실시간으로 갱신되는 것이 보이는데
        필드는 render()을 호출하지 않기 때문에 웹에서 실시간으로 갱신됨이 보이지 않는다. */}
      </div>
    );
  }
}

export default App;

- 버튼 1을 누를 때 즉각적으로 값이 갱신되지만 버튼2를 누르면 바로 값이 갱신되지 않는다. 

- 버튼 1(state 변수 사용)이 render() 함수를 호출하기 때문에 버튼 1을 누를 때 갱신한 버튼 2의 값이 같이 변경되어 출력된다.

Ex02 실행결과
Ex02 콘솔 출력결과

  • Ex03 (import의 사용)

기본 src 폴더 ( ./ )

- 기본 폴더 src에서 외부의 컴포넌트와 함수를 사용하려면 export를 붙여 선언해야 한다.

- default 컴포넌트가 선언된 컴포넌트에는 export가 암묵적으로 선언되어 있기 때문에 선언하지 않아도 된다.

// App.js

import React, { Component } from 'react';
import Bpp, { Cpp, Dpp } from './apple/bpp.js'
// *은 모두 다 쓰겠다.
// Fpp로 외부의 함수를 끌어다 쓰겠다.
// fpp.js에 있는 함수 들을 Fpp가 받는다.
import * as Fpp from './apple/fpp.js'
// gpp.js에는 함수도 불러오고 컴포넌트도 불러오고 싶을경우에
// 둘다 한번에 부르려고 하기보다는 각각 불러라.
import Gpp, { Hpp } from './apple/gpp.js'
import * as GppFu from './apple/gpp.js'
import Ipp from './apple/sub1/ipp.js'

// 폴더만 지시(이 폴더안에는 반드시 index.js가 반드시 한개 존재해야 한다. 없으면 error)
// 폴더안에 index.js 파일을 생성해주면 error가 풀린다.
// index.js가 App.js와 똑같다고 보면 된다.
// 폴더명 자체가 태그다.
// 폴더의 메인인 index.js를 호출한다.
import Sub3 from './apple/sub3'

// 사용 할 것은 bpp.js 이지만 Opp로 선언해서 사용 가능(변수처럼)
// 하지만 export default가 선언된 것만 사용 가능
// { Cpp } 선언 안하면 error
// {} 안은 bpp.js에 있는 default 가 아닌 컴포넌트(클래스)를 사용 할 때 선언
//import Opp, { Cpp } from './apple/bpp.js'


// 필요에 따라 클래스 밖에 선언해서 전역으로 사용
function f1() {
  console.log('f1()');
  
}

class App extends Component {
  render() {
    f1()
    Fpp.f2();
    Fpp.f3();
    GppFu.f4();
    return (
      <div>
        <Bpp></Bpp>
        <Cpp></Cpp>
        <Dpp></Dpp>
        <Gpp></Gpp>
        <Hpp></Hpp>
        <Ipp></Ipp>
        {/* Sub3가 폴더로 import 한 것이다.  */}
        <Sub3></Sub3>
      </div>
    );
  }
}

export default App;

-----------------------------------------------------------------------------------------------------------------------------------

apple폴더의 bpp.js, fpp.js, gpp.js ( ./apple/bpp.js, fpp.js, gpp.js )

// bpp.js

import React, { Component } from 'react';

class Bpp extends Component {
    render() {
        return (
            <div>
                <h1>Bpp</h1>
            </div>
        );
    }
}

// 현재 파일에서 Bpp에서 쓸 수 있는데 외부에서 사용 할러면 export를 붙여줘야 사용 할 수 있다.
// export가 없다면 아래와 같은 error
/* ./src/App.js
Attempted import error: 'Cpp' is not exported from './apple/bpp.js'. */
export class Cpp extends Component {
    render() {
        return (
            <div>
                <h1>Cpp</h1>
            </div>
        );
    }
}

export class Dpp extends Component {
    render() {
        return (
            <div>
                <h1>Dpp</h1>
            </div>
        );
    }
}

export default Bpp;
// fpp.js

// 외부에서 함수 선언
// 외부에서 사용을 위해서는 함수도 export 붙여 줘야 한다.

export function f2 () {
    console.log('f2()');
    
}

export function f3 () {
    console.log('f3()');
}
// gpp.js

import React, { Component } from 'react';

// export로 선언을 해주어야 외부에서 사용이 가능하다.
export function f4() {
    console.log('f4()');
    
}

// default는 자동으로 export가 정의되어 있다.
class Gpp extends Component {
    render() {
        return (
            <div>
                <h1>Gpp</h1>
            </div>
        );
    }
}

// default 컴포넌트가 아니기 때문에 export를 선언해 주어야 외부에서 사용가능하다.
export class Hpp extends Component {
    render() {
        return (
            <div>
                <h1>Hpp</h1>
            </div>
        );
    }
}

export default Gpp;

-----------------------------------------------------------------------------------------------------------------------------------

apple폴더의 sub1 폴더의 ipp.js ( ./apple/sub1/ipp.js )

// sub1 폴더의 ipp.js

import React, { Component } from 'react';

// ../는 현재 폴더의 상위 폴더
import Jpp from '../sub2/jpp.js'

class Ipp extends Component {
    render() {
        return (
            <div>
                <h1>Ipp</h1>
                <Jpp></Jpp>
            </div>
        );
    }
}

export default Ipp;

-----------------------------------------------------------------------------------------------------------------------------------

apple폴더의 sub2 폴더의 jpp.js ( ./apple/sub2/jpp.js )

// sub2 폴더의 jpp.js

import React, { Component } from 'react';

class Jpp extends Component {
    render() {
        return (
            <div>
                <h1>Jpp</h1>
            </div>
        );
    }
}

export default Jpp;

-----------------------------------------------------------------------------------------------------------------------------------

apple폴더의 sub3 폴더의 index.js, bpp.js, cpp.js ( ./apple/sub3 )

- 폴더 단위로 넘겨 사용을 하고 싶다면 index.js가 반드시 존재해야 한다.

- 폴더 단위로 import 해서 사용하게 된다면 이미 구현된 컴포넌트를 그대로 가져와 사용 할 수 있다는 장점이 있다.

// sub3 폴더의 index.js

// Apple이 Main이 된다. 즉, index.js가 메인 컴포넌트가 된다.
// 즉, sub3 폴더의 Main은 index.js 이므로 폴더를 import하게 되면 index.js가 실행이 된다.
// 그렇기 때문에 index.js는 또 sub3 폴더 내의 다른 컴포넌트를 import 한다.
// 그러면 이미 구성된 컴포넌트를 폴더 단위로 관리하여 끌어다 사용을 할 수 있다는 장점이 있다.

import React, { Component } from 'react';
import Bpp from './bpp.js'
import Cpp from './cpp.js'

class Apple extends Component {
    render() {
        return (
            <div>
                <Bpp></Bpp>
                <Cpp></Cpp>
            </div>
        );
    }
}

export default Apple;
// sub3 폴더의 bpp.js

import React, { Component } from 'react';

class Bpp extends Component {
    render() {
        return (
            <div>
                <h1>Apple의 Bpp</h1>
            </div>
        );
    }
}

export default Bpp;
// sub3 폴더의 cpp.js

import React, { Component } from 'react';

class Cpp extends Component {
    render() {
        return (
            <div>
                <h1>Apple의 Cpp</h1>
            </div>
        );
    }
}

export default Cpp;

Ex03 실행결과
Ex03 현재 콘솔 출력결과