728x90

JavaScript와 HTML,CSS등에 대해서는 일체 다루지 않는다.

기초 지식은 다른 강의를 참조하도록 하라.

이 강의는 React의 사용법 위주로 작성되어 있다.

왜 React여야는지, React를 써야하는지에 대하지는 논하지 않으므로 그런 자료는 다른 데이터를 참조하라.


참조:

react docs 


힘들게 2시간 가량 쓴 글이 허공이 날라갔다.

하지만 다시 글을 써야한다... 내 시간 돌려줘.


redux는 react에게 한줄기 광명같은 존재이지만 사실 굉장히 좋다고 말하기는 무리가 있다고 생각이든다.

그 이유는 redux를 사용한 flux구조에서 오는 단점, 그리고 redux 자체가 쓰기가 조금 복잡하다는 이유도 있다.

그리하여 추가된 어뎁터가 있는데 바로 react-redux이다.


https://react-redux.js.org/


공식 홈페이지는 위와 같다. react-redux에서는 핵심 가치를 위처럼 표현하고 있는데 다 뜬 구름 잡는 소리같다.

필자가 생각하는 쌩 redux보다 react-redux를 함께 썼을 때의 장점은 아래와 같다.


1.기존의 redux를 쓰게 되면 필연적으로 react의 코드 구조에 변화가 온다. 이를 최대한 막아준다.

2.redux구조를 쓰면 모듈화해서 사용하기 불편해지고 다른 모듈에서 쓰기도 까다로운데 react-redux를 쓰면 편해진다.


이런 종류를 helper라고하는데 vue도 helper를 쓰는게 대세이다.

flux구조에서 helper들을 붙혀서 좀더 모듈화의 느낌을 살릴 수 있고 불필요한 코드를 삭제하고 코드를 읽히게 하는데 더 도움을 준다.



npm install --save react-redux


먼저 사용하기 전에 반드시 react-redux를 설치해줘야한다.

너무나도 당연한 말이다.


https://github.com/justkukaro/react-test-project/tree/master/redux

https://github.com/justkukaro/react-test-project/tree/master/react-redux


redux를 썼을 때와 redux와 react-redux를 함께 썼을 때를 비교하면서 볼 것이다.

redux만 사용한 예제는 전 포스팅에서 다뤘던 내용이므로 참고하면 좋을 것이다.


한번에 설명하기 보다는 부분 부분 나눠서 설명하는 것이 좋을 것같으므로 예제를 통해서 함께 보도록 하자.


Provider로 이 프로젝트가 redux의 영향 하에 있다는것을 알리자


// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import {createStore} from 'redux';
import reducers from './reducers';

const store = createStore(reducers);

const render = ()=> {
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
);
};
store.subscribe(render);
render();

기존 redux만 사용한 프로젝트의 경우 위처럼 사용했다.

이게 아래처럼 바뀌게 된다.


// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import {createStore} from 'redux';
import {Provider} from 'react-redux'
import reducers from './reducers';

const store = createStore(reducers);

const render = () => {
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
};
store.subscribe(render);
render();

보면 알겠지만 App을 Provider로 감싼다.

Providersms react-reduxs내부에 존재하는 컴포넌트이다.

그리고 store를 App이 아닌 Provider에 연결해준다.

이로 인해서 얻는 장점은 더이상 store를 부모가 자식에게 재산 물려주듯 내려줄 필요가 없다는 것이다.


mapStateToProps


// App.js
import React, {Component} from 'react'
import AddButton from './AddButton'
import SubButton from './SubButton'

class App extends Component {

render() {
return (
<div className="App">
<span>{this.props.store.getState().data.number}</span><br/>
<AddButton store={this.props.store}/><SubButton store={this.props.store}/>
</div>
);
}
}

export default App;

기존 redux만 사용한 페이지는 위처럼 사용하였다.

짜증 나는점은 store에서 저렇게 길게 호출하는것이 짜증난다는점,

그리고 항상 store를 내려줘야한다는 점이다.

이를 react-redux에서는 타개하게 된다.


// App.js
import React, {Component} from 'react'
import {connect} from 'react-redux'
import AddButton from './AddButton'
import SubButton from './SubButton'

class App extends Component {

render() {
return (
<div className="App">
<span>{this.props.number}</span><br/>
<AddButton/><SubButton/>
</div>
);
}
}

let mapStateToProps = (state, /*ownProps*/) => {
return {
number: state.data.number,
};
};

App = connect(mapStateToProps, null)(App);

export default App;

달라진건 span태그에 선언한게 props라는 점이다.

우리는 분명 부모에 컴포넌트에서 number라는 props를 내려준 적이 없다.

이는 사실 최종 props(혹은 가짜 props)인데 추후에 언급하겠다.

어쨋든 redux에서 불러올 녀석도 props라는 이름을 정할 것이다.


또 아래에 봐야할건 mapStateToProps이다.


let mapStateToProps = (state, /*ownProps*/) => {
return {
number: state.data.number,
};
};

이게 뭘 의미하냐면 state라는 변수를 받아 왔을 때 해당 페이지의 this.props.number와 store(redux)내에 존재하는 data.number와 연결시켜준다는 이야기이다.

그리고 data.number변화를 감지해서 this.props.number에 반영하게 된다.


두번째 파라메터로 ownProps가 주석처리 되어있다.

이를 여러분들이 사용할 수도 있다. 이 때 ownProps는 App 컴포넌트 내의 진짜 props를 의미한다.

진짜 props가 뭔지는 아래에 후술하겠다.



마지막으로 connect를 사용해서 연결한다.

connect는 총 4개의 파라메터를 받는데 여러분이 필요한것만 사용하면 된다.

만약 사용하지 않는다면 비워두거나 null혹은 undefiend를 주면된다.

위의 예제에서 우리는 변수의 변화를 감지할 것이므로 mapStateToProps를 사용할 것이다.


실제로는 1번과 2번만 주로 사용하고 3번과 4번은 거의 사용하지 않는다.

거의 사용하지 않는 정도가 아니라 예제도 보기 힘들정도이다.



mapStateToProps는 첫번째 인자이다.

즉 connect에서 첫번째 인자를 달아주려면 이녀석으로 달아줘야한다.


이제 여러분은 redux와 연결되어서 redux에서 number의 값을 바꾸면 변동을 감지할 수 있게 된다.


mapDispatchToProps


// AddButton.js
import React, {Component} from 'react';
import {add} from './actions'

class AddButton extends Component {

render() {
return (
<input value={'+'} type="button" onClick={this.addNumber}/>
)
}

addNumber = () => {
this.props.store.dispatch(add());
}
}

export default AddButton;

redux만 사용할 경우 위처럼 우리가 redux로 dispatch를 하기 위한 전용함수를 만들어 줬어야한다.

위의 경우 addNumber가 이에 해당한다.

그래서 큰 내용이 없는 경우 익명함수로 그냥 냅다 붙히는 경우도 많다.


// AddButton.js
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {add} from './actions'

class AddButton extends Component {

render() {
return (
<input value={'+'} type="button" onClick={this.props.addNumber}/>
)
}
}

let mapDispatchToProps = (dispatch, /*ownProps*/) => {
return {
addNumber: () => dispatch(add())
};
};

AddButton = connect(null, mapDispatchToProps)(AddButton);

export default AddButton;

하지만 react-redux에서는 그냥 내부에 메소드를 선언하지 않는다.

대신에 mapDispatchToProps를 사용해서 함수를 직접 붙혀줄 뿐이다.


mapDispatchToProps는 인자로 dispatch와 ownProps를 받는다.

당연히 ownProps는 해당 컴포넌트의 진짜 props를 의미한다.

그리고 위의 this.props.addNumber도 진짜로 props는 아니고 최종 props이다.

어쨋든 이제 버튼을 누르면 바로 store에 dispatch되게 된다.


이제 프로젝트를 돌려보면 제대로 돌아가는걸 확인할 수 있다.


mergeProps



가끔씩 가뭄에 콩나게 사용되는 경우가 있다.

주 역활은 mapStateToProps나 mapDispatchToProps가 동작하면 따라서 동작하게 되어있다.

그래서 뒤에서 추가적인 역활을 할 때 사용한다.

자주 사용하진 않는다.


App = connect(mapStateToProps, null,
(stateProps, dispatchProps, ownProps) => {
console.log(stateProps, dispatchProps, ownProps);
return {
number: stateProps.number + 10
};
}
)(App);

동작확인을 위해서 다음과같이 코드를 수정해서 사용해보자.



여러분은 꽤나 놀라운걸 목격할 수 있다.

목격 못했다면 이제부터 설명할테니까 걱정은 안해도 된다.

먼저 화면에 11이 출력됬지만 stateProps(실제로 redux에 저장되어 있는 state)는 1이라는 점이다.

위 코드로 우리는 stateProps에서 number에 10을 더했지만 실제 redux저장소에는 영향을 안미친다는 것이다.


그런데 실제 컴포넌트의 props역시 빈 오브젝트이다.

그럼 우리가 선언하는 this.props.number의 정체가 뭘까?
위에서도 언급했지만 이는 실제 props가 아니라 "최종 props"이다. 다른 말로는 가짜 props이다.

react-redux를 쓰면서 쓰는 props들은 코딩의 편함을 위해서, 원자 구조를 지키기위해서 만들어진 개념일 뿐,

실제로는 진짜로 props는 아닌, 문법적 설탕이라는 것이다.


어쨋든 여러분들은 react-redux를 사용함으로써 react에서 사용되었던 불편한점이 많이 개선되었다.

경우에 따라선 더 불편할 수도 있지만 보는 관점이나 코딩하는 관점에서는 개선됬다고 보는게 맞는것 같다.

+ Recent posts