AddNumberRoot.jsx, DispalyNumberRoot.jsx는 프레젠테이션 컴포넌트
AddNumber.jsx, DisplayNumber.jsx는 컨테이너 컴포넌트로 나누도록 하겠습니다.
일단 구조는 데이터를 받아 화면에 뿌려주기만하는 컨테이터 컨포넌트 components 폴더를 만들고, 그 안에 AddNumber.jsx, AddNumberRoot.jsx, DisplayNumber.jsx, DisplayNumberRoot.jsx파일들을 만들어 줍니다.
다음은 데이터를 가공하여 컨터이너 컨포넌트에 전달해주는 프레젠테이션 컴포넌트 containers폴더를 만들고, 그 안에 AddNumber.jsx, DisplayNumber.jsx파일들을 만들어 줍니다.
이번에는 Redux를 적용한 예제를 만들어 보겠습니다.
현재 예제는 class 컴포넌트를 사용한 예제입니다.
전 게시글에서 만들었던 화면과 동일한 예제입니다.
일단 구조는 src폴더 안에 컨포넌트 components 폴더를 만들고, 그 안에 AddNumber.jsx, AddNumberRoot.jsx, DisplayNumber.jsx, DisplayNumberRoot.jsx파일들을 만들어 줍니다. 그런 다음에 App.js에 하위 컴포넌트에 전달하는 props들을 제거 하도록 하겠습니다.
redux를 사용하지 않은 예제를 변경할 경우 import 경로를 변경해주시기바랍니다.
import React, {Component} from 'react'; import './App.css'; import AddNumberRoot from './components/AddNumberRoot'; import DisplayNumberRoot from './components/DisplayNumberRoot'; class App extends Component { render(){ return ( <div className="App"> <h1>Root</h1> <AddNumberRoot></AddNumberRoot> <DisplayNumberRoot></DisplayNumberRoot> </div> ); } } export default App;
변경된 내용
1. import 경로 변경
2. state 제거
3. 하위 컴포넌트의 속성들 제거 (props)
AddNumberRoot.jsx도 props값을 받은게 없으니 속성들을 제거해줍니다.
import React, { Component } from "react"; import AddNumber from "../components/AddNumber"; export default class AddNumberRoot extends Component { render() { return ( <div> <h1>Add Number Root</h1> <AddNumber></AddNumber> </div> ); } }
변경된 내용
1. AddNumber에 보낼 속성 값 제거
DisplayNumberRoot.jsx도 props값을 받은게 없으니 속성들을 제거해줍니다.
import React, { Component } from "react"; import DisplayNumber from "../components/DisplayNumber"; class DisplayNumberRoot extends Component { render() { return ( <div> <h1>Display Number Root</h1> <DisplayNumber></DisplayNumber> </div> ); } } export default DisplayNumberRoot;
이렇게 하위 컴포넌트에게 프로퍼티를 주지 않았기때문에 동작을 하지 않을겁니다.
왜냐하면 상위컴포넌트에서 state를 변경해줘서 리랜더링이 되어 화면에 뿌려져야하기 때문입니다.
다음은 store.js 파일을 만들어보도록하겠습니다.
store는
상위컴포넌트든지 하위컴포넌트에서든지 state를 가져 올 수 있습니다.
아래 코드를 보겠습니다.
export default createStore(function(state, action){ if(state === undefined){ return {number :0} } if(action.type === 'INCREMENT'){ return {...state, number: state.number + action.size} } return state; }, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
redux의 내장함수 createStore를 받아와 store를 만들어 줍니다 이때 함수는 2개의 인자값을 받아와 state값에 변화를 일으키는 함수입니다. 현재의 state와 전달받은 action을 참고하여 새로운 state를 return해줍니다.
createStore 에서 코딩한 함수는 Reducer라고 생각하시면 됩니다.
안에 코드를 보면 state값이 undefiend이면 초기값을 지정해주고 state.type이 "INCREMENT"이면 state.number에 현재값 + 가져온 값을 합하여 state를 변경하여 return해주는 코드입니다.
그리고 createStore에 두번째 인자 window.REDUX_DEVTOOLS_EXTENSION && window.REDUX_DEVTOOLS_EXTENSION() 는 개발자도구에서 redux를 추가 해주는 겁니다.
이렇게 store를 만들어 줬으면 이제 AddNumber.jsx파일을 변경해보도록하겠습니다.
import React, { Component } from "react"; import store from "../store"; export default class AddNumber extends Component { state = { size: 1 }; render() { return ( <div> <h1>Add Number</h1> <input type="button" value="+" onClick={(e) => { store.dispatch({ type: "INCREMENT", size: this.state.size }); }} </input> <input type="text" value={this.state.size} onChange={(e) => { if (e.target.value === "" || e.target.value === null) { this.setState({ size: parseInt(0) }); } else { this.setState({ size: parseInt(e.target.value) }); } }} </input> </div> ); } }
변경된 내용
1. import store from "../store"; store 임포트 추가
2. onClick 이벤트에 store.dispatch({ type: "INCREMENT", size: this.state.size });로 변경
store.dispatch함수를 호출 할때 인자값{type: "INCREMENT, size: this.state.size"}은 createStore의 함수인자값 중 action으로 들어가지게됩니다.
dispatch함수는 reducer를 실행하여 state값을 변경해줍니다.
여기까지 했으면 AddNumber의 입력값이 변하는거는 확인하실 수 있습니다.
이 다음에는 버튼을 클릭하여 DisplayNumber에 값이 노출되게 만들어보겠습니다.
아래 코드를 보겠습니다.
import React, { Component } from "react"; import store from "../store"; class DisplayNumber extends Component { state = {number:store.getState().number} constructor(props){ //초기값 super(props); store.subscribe(function() { //store가 변경되었을때 호출이 된다. this.setState({number : store.getState().number}); }.bind(this)); } render() { return ( <div> <h1>Display Number</h1> 합 : <input type="text" value={this.state.number} readOnly></input></input> </div> ); } } export default DisplayNumber;
변경된 내용
1. import store from "../store"; store 임포트 추가
2. state 또는 객체 선언할 때 사용하는 constructor를 사용하여 초기세팅을 해줍니다.
3. 텍스트박스의 값가져오는 법 변경
여기에서 getState() 는 store에 저장된 state를 가져옵니다.
단. 읽기만 가능하고 변경을 불가합니다.
그리고 subscribe() 는 store가 변경되었을 때 호출이 되어 함수를 실행시켜, 화면을 변경된 값으로 보여주기위해 사용합니다.
이렇게 코드를 작성하면 Redux를 사용하지 않고 만든 예제랑 동일하게 작동되는 걸 확인 할 수 있습니다.
다음 시간에는 connect를 사용한 예제를 해보겠습니다.