지난주 복습
React의 열두가지 컨셉을 배우는것이 목적이다.
![](https://blog.kakaocdn.net/dn/FlkBp/btqBDbl36sy/nGiKS0FLmEsIyRek7AIGxK/img.png)
시간에따라 변하는데이터의 조건
1)setState
2)mergy
3)비동기 처리
-> localState로는 Player의 합계 점수를 구할수가 없었다. (각자 자신의 상태값만 가지고 있기 때문이다.)
-> 이러한 문제를 해결하기 위해서 score를 최상단 컴포넌트로 올려줬고, 이를 Lifting state Up 라고 한다.
-> 최상단 컴포넌트에서 state를 갖고, Props로 내려줬었다.
but +/- function은 Player에서 가질 수 없다. 최상단 컴포넌트에서 관리를 해야한다.
-> 따라서 +/- function을 최상단 컴포넌트에서 생성 후 Props로 함수를 내려준다. 그리고 Player에서는 이를 호출한다
여기까지가 리액트에서 가장 많이 차지하고 있는 부분
-> Props를 내려주는것은 번거롭다... 단계, 단계로 내려줘야 하기 때문.. 중간에 컴포넌트가 빠지면 리팩토링 해줘야함..
->이러한 문제를 해결하기 위해 redux로 이어진다.! 최상위 부모가 State를 관리하는것이 아니라 Redux가 가지고 있는 Store에 보관한다.
-> 모든 자식은 Store에서 데이터를 내려받는다.
![](https://blog.kakaocdn.net/dn/YOWeS/btqBFM6cvGc/scKh5pVtFLfp2kz9yy6CwK/img.png)
* 기존 scoreBoard 프로젝트에 통계기능을 추가하자
곁다리 1)
*Template 생성
![](https://blog.kakaocdn.net/dn/b1NSCB/btqBFv4Jaap/2GwBWTa5Pllh7ZdPUzvzk1/img.png)
![](https://blog.kakaocdn.net/dn/eawb9m/btqBEz0OqJN/gyIaQmkuU2nT81loobDiZ0/img.png)
![](https://blog.kakaocdn.net/dn/cgug0S/btqBFNxi99Z/Yz9xXXFvD3VaKklIaH9NUK/img.png)
1) App에서 players 배열을 Props로 새로 만든 States 컴포넌트로 보내준다.
![](https://blog.kakaocdn.net/dn/GSyjx/btqBE0Yb8ux/XvGGmpV1KEgV7SSnLb0Ksk/img.png)
2) States는 그것을 받아서 총 인원과 토탈 점수를 구해준다.
![](https://blog.kakaocdn.net/dn/bGHeMP/btqBE1QlrZ9/K4ksUL8swl3pWUCxn5KLkK/img.png)
3) 동작을 확인한다.
![](https://blog.kakaocdn.net/dn/cdojP5/btqBCTMHhjT/u4wURi4YYi4xkQdqkgCQwK/img.png)
곁다리
lodash
lodash라는 라이브러리를 공부하자. 개발을 계속 할거면 - https://lodash.com/
![](https://blog.kakaocdn.net/dn/b6TNR8/btqBE1JzZMG/kvjj5V8DGklfNedZTRtxmk/img.png)
Examples
객체를 받아서 합계를 구해서 반환해준다- 와 편하다...
![](https://blog.kakaocdn.net/dn/Ng0uN/btqBD2PLaTD/yWtEHkKq9c7fqHGJ5d4nZk/img.png)
![](https://blog.kakaocdn.net/dn/dj1RVh/btqBFuSgbg8/7yNkK9YsjqxeCpIC3z2CSk/img.png)
Controlled Components
<->UnControlled Components
*상태를 가지고 있기 때문에 class Component로 만든다.
HTML element는 자기 자신의 state를 가지고 있고, 사용자의 입력에 따라 그 state를 업데이트한다. 리액트에서는 이와 같이 mutable state는 컴포넌트의 state 속성에 정의하고 setState로 업데이트해야 한다. 그러므로 input form은 리액트에서 컨트롤되어야 하는데 이와 같은 컴포는트를 controlled component라고 한다. 사용자가 input을 입력하면 바로 상태가 바뀌고 바뀐 상태가 바로 리렌더링되서 화면에 보여주게 된다. input 의 value를 controlled component로 만들어보자.
1) 먼저 시간에 따라 변하는 입력값을 state에 value로 정의하고 input에 value와 연결한다. 그리고 테스트해보자. input 에 값을 넣으면 값이 입력이 되는가? 입력이 되지 않고 하단 warning을 확인해보자. onChange 이벤트를 구현하라고 나올것이다.
import React from 'react'; export class AddPlayerForm extends React.Component { state = { value: '' } handleValueChange(e) { console.log('handleValueChange', e); } render() { return ( <form action="" className="form"> /*React는 React함수(C가 대문자)를 사용하면 이벤트 객체를 자동으로 넘겨준다.*/ <input type="text" className="input" value={this.state.value} onChange={this.handleValueChange} placeholder="enter a player's name"/> {/*시간에 따른 데이터를 관리하기 위해 state를 정의한다.*/} <input type="submit" className="input" value="Add Player"/> </form> ) } } // e말고도 다른 파라미터를 넘기고 싶으면 onChange={(e, param1) => this.handleValueChange(e, param1)}
![](https://blog.kakaocdn.net/dn/cYRrNG/btqBE2aFTVs/FMLcWKCxCfcRWFNNjTfDh1/img.png)
만약 value만 선언하고 onChange를 넣지 않으면 에러가 된다.
값을 변경하는방법은 setState밖에 없는데 setState를 정의하지 않아서 에러가 나는것.
리액트는 one way binding이라서 input 박스에 값을 입력하면 onChange함수를 구현해야 한다.
=> 모델을 정의하고 바인딩해야 View에 반영된다. inputBox에 입력을한다고해서 바로 반영되는것이 아니란 말이다.
import React from 'react'; export class AddPlayerForm extends React.Component { state = { value: '' } handleValueChange = (e) => { this.setState({value: e.target.value}) //이벤트 객체의 target > value로 이동한다. input값을 변경하는것이기 때문에 비동기 처리가 필요없다. } render() { return ( <form action="" className="form"> <input type="text" className="input" value={this.state.value} onChange={this.handleValueChange} placeholder="enter a player's name"/> <input type="submit" className="input" value="Add Player"/> </form> ) } }
새로운 Player를 추가하기
AddPlayerForm은 입력된 값만 App(Root Component)에 넘기면 된다.
=> App에서 생성한 함수를 AddPlayerForm에 넘겨주면 된다. 지난주 복습과 동일
Submit하게되면 페이지를 리로딩 하게된다...! => 메모리에 있는 변수 정보가 전부 날아가게 된다. singlePage기 때문 ㅠ
-> 리덕스도 마찬가지다. 페이지 리로딩이 일어나면 값 보존이 안된다. ->localStorage에 넣어준다..!
submit 이벤트는 기본 이벤트가 다른 페이지로 전환하게 되므로 preventDefault() 를 사용하여 기본 이벤트를 막아야 한다. 만일 기본 이벤트를 막지 않으면 페이지가 리로드 되면서 모든 상태 변수들이 초기화가 된다. SPA에서는 페이지 리로드가 일어나지 않도록 주의해야 한다.
*갖고있는 값을 넘기기
전체적인 구조는 사용자가 값을 입력할때마다 state를 업데이트하고, 사용자가 submit을 누르는 순간 부모 컴포넌트인 App에 이 값을 넘기는 함수를 호출한다.
*App에서 새로운 Player를 추가하는 handleAppPlayer 구현
//내코드
문제점 1) prevState를 활용하지 못함(...)
//내가 짠 코드.. 이뮤터블 함수에 대한 이해가 부족하다..끙.. //아마 state에 있는 객체들의 메모리 주소가 변하지 않으면.. 값이 변하지 않았다고 인식하는것인가.? handleAppPlayer = (name) => { //console.log('handleAppPlayer') this.setState(prevState =>{ this.state.players.push({name:name, score: 0, id:5}); /* return this.state.players = prevState.players.map(function(value){ return value; //객체를 반환 }) */ }) }
//강사님이 짠 코드
a.이뮤터블 하지 못하다. handleAppPlayer = (name) => { this.setState(prevState =>{ prevState.players.push({name:name, score: 0, id:5}); return {players: prevState.players}; //이전상태의 배열값을 넘긴다. }) } b. deepCopy를 함으로써 이뮤터블하다. handleAppPlayer = (name) => { this.setState(prevState =>{ const players = [...prevState.players]; //deepCopy 새로운 메모리에 복사 players.push({name:name, score: 0, id:++maxId}); return {players: players}; }) }
HTML5 Validation
Validation API가 추가가 되므로써 아주 간단해졌다.
input에 required 속성만 추가하면 된다.
html5 validation을 하지 않기 위해서는 form에 noValidate 를 추가한다.
![](https://blog.kakaocdn.net/dn/eI6acr/btqBGfG9mCe/0cGkee0lKVPYkKXSHCWDi0/img.png)
React에서 HTML기본 Validation을 사용하지 않으려면 form에 noValidate를 추가한다.
form의 유효성을 체크하기위해서 checkValidity(), 입력 노드의 유효성성은 validity.valid로 체크한다.
handleSubmit = (e) => { e.preventDefault(); const form = document.getElementById("form"); const player = document.getElementById("player"); console.log(form.checkValidity()); console.log(player.validity.valid); if(!form.checkValidity()){ //에러문구 노출 return; } this.props.addPlayer(this.state.value); } render() { return ( <form id="form" action="" className="form" onSubmit={this.handleSubmit} noValidate> <input id="player" type="text" className="input" value={this.state.value} onChange={this.handleValueChange} placeholder="enter a player's name" required/> <input type="submit" className="input" value="Add Player"/> </form> ) }
곁다리 1)
HTML5 기능들
* 이미지를 멀티파트가 아니라 JSON으로 넘기기
곁다리 2)
console.log("A"); setTimeout(function () { console.log("B"); }, 0); console.log("C");
JS: 비동기함수는 큐에 들어가서 실행을 대기하게 된다. 싱글스레드 이기 때문에 큐에있는 잡도 메인쓰레드가 처리한다.
=> main스레드가 쉬고있는 시간에 실행을 한다.
그래서 항상 실행결과는 ACB가 된다.
반면 JAVA: 멀티쓰레드 환경. Thread들이 경쟁하면서 실행하게 된다. ABC가 될지 ACB가 될지 모른다.
그래서 극단적인 예를들면 메인스레드가 무한루프에 빠지면 큐에있는 잡은 절대 실행이 안된다.
console.log("A"); setTimeout(function () { console.log("B"); }, 0); console.log("C"); while(true) {}
*라이프사이클의 이해 StopWatch 추가
import React from 'react'; export class StapWatch extends React.Component { tickRef; //Dom이 렌더링 된 직후에 호출된다. //Rest API호출, 3rd 라이브러리 로딩하는 부분이 여기 들어가야 한다. //React가 호출해주는 함수. //렌더링이 되야 DOM을 붙일수가 있는데 서버에서 데이터를 아직 안넘어온상태면 모탐 componentDidMount() { this.tickRef = window.setInterval(() =>{}, 1000); } // DOM이 파괴되기 직전에 호출 // 리소스 해제 등 but 브라우저 종료시에는 동작하지 않음.. componentWillUnmount() { clearInterval(this.tickRef); //Interval 상태해제 } render() { return ( <div className="stopwatch"> <h2>StapWatch</h2> <span className="stopwatch-time">0</span> <button>Start</button> <button>Reset</button> </div> ) } }
//Stop | Start 토글 만들기
import React from 'react'; export class StapWatch extends React.Component { tickRef; state = { isRunning: false } componentDidMount() { this.tickRef = window.setInterval(() =>{}, 1000); } componentWillUnmount() { clearInterval(this.tickRef); } render() { return ( <div className="stopwatch"> <h2>StapWatch</h2> <span className="stopwatch-time">0</span> <button> { this.state.isRunning ? 'Stop' : 'Start' } </button> <button>Reset</button> </div> ) } }
import React from 'react'; export class StapWatch extends React.Component { tickRef; state = { isRunning: false, timer: 0 } componentDidMount = () => { this.tickRef = window.setInterval(() =>{ if(this.state.isRunning){ this.setState(prevState =>{ return{ timer: prevState.timer + 1 } }) } }, 1000); } componentWillUnmount() { clearInterval(this.tickRef); } handleStopWatch = () => { this.setState(prevState =>{ return { isRunning: !prevState.isRunning }; //JSON객체를 return할때는 {}가 있어야 함. }) } render() { return ( <div className="stopwatch"> <h2>StapWatch</h2> <span className="stopwatch-time">{this.state.timer}</span> <button onClick={this.handleStopWatch}> { this.state.isRunning ? 'Stop' : 'Start' } </button> <button onClick={() => this.setState({timer: 0})}>Reset</button> </div> ) } }
'Today I learned' 카테고리의 다른 글
React Hook (0) | 2020.02.08 |
---|---|
[react] 3 주차 redux (2) (0) | 2020.02.01 |
[AWS] 20/01/30 AWS 세미나 참석 (0) | 2020.01.30 |
[AWS] 생활코딩 AWS 강의 정리 - EC2설정 및 Apache 설치 (0) | 2020.01.27 |
[SQL] 생활코딩 SQL 조인 강의 정리 (0) | 2020.01.27 |
댓글