React 정리 #4
in Devlog on Bit
React 정리 #4
실습 #1
- props로 기본 필드, state 필드, 함수 등을 받아올 수 있고 보낼 수 있다.
import React, { Component } from 'react'
import Sample from './190808_sample'
export default class App extends Component {
state = {
animal_ar : ['호랑이', '코끼리', '토끼'],
}
render() {
return (
<div>
<ol>{
this.state.animal_ar.map((v, k) => {
return <li>{v}</li>
})
}
</ol>
<button onClick={() => {
this.setState({
animal_ar: this.state.animal_ar.concat('독수리')
})
}}>독수리 버튼</button>
</div>
)
}
}
실습 #1
import React, { Component } from 'react'
import Bpp from './bpp'
export default class App extends Component {
state = {
animal : ['호랑이', '코끼리', '앵무새'],
}
animalEvent = () => {
let num = Math.floor(Math.random() * 3)
this.setState({
animal_name : this.state.animal[num],
})
}`
render() {
return (
<div>
<h1>{this.animal_name}</h1>
<Bpp animalEvent = {this.animalEvent}/>
</div>
)
}
}
실습 #1
- 알림창
import React, { Component } from 'react'
export default class App extends Component {
// 알림창 띄우는 3개
f1 = () => {
// 알림창
alert("안녕하세요")
}
f2 = () => {
// 입력가능한 알림창
// 입력 결과값이 리턴된다. (취소시 null)
let result = prompt("안녕하세요", "입력하세요")
console.log(result);
}
f3 = () => {
// 확인,취소 알림창
// 입력 결과값이 리턴된다. (확인 true, 취소 false)
let result = window.confirm("정말 삭제하시겠습니까?")
console.log(result);
}
f4 = (e) => {
console.log("입력");
console.log(e.target.value);
}
f5 = (e) => {
this.setState({
txt : e.target.value
})
}
state = {
txt: "내용",
text: ""
}
render() {
return (
<div>
<button onClick = {this.f1}>f1</button>
<button onClick = {this.f2}>f2</button>
<button onClick = {this.f3}>f3</button>
{/* 익명함수를 통하여 alert 호출 */}
<button onClick = {() => {alert("글쎄요..")}}>글쎄요 버튼</button>
<input
//객체의 속성이기 때문에 콤마(,)를 사용하지않음.
type = {Text}
name = "메세지"
placeholder = "값을 입력하세요!"
onChange = {this.f5}
// input 태그는 한줄로 죽 안쓰기 때문에 엔터
/>
<button onClick = {() => {alert(this.state.txt)}}>알람</button>
</div>
)
}
}
import React, { Component } from 'react'
import Sample from './190808_sample'
export default class App extends Component {
state = {
animal_ar : ['호랑이', '코끼리', '토끼'],
}
render() {
return (
<div>
<ol>{
this.state.animal_ar.map((v, k) =>
{
return <li onClick = {() => {
this.setState({
animal_ar: this.state.animal_ar.slice(0, k).concat(this.state.animal_ar.slice(k + 1, this.state.animal_ar.length))
})
}}
key = {k}>{v}</li>
})
}
</ol>
<button onClick={() => {
this.setState({
animal_ar: this.state.animal_ar.concat('독수리'),
})
}}>PUSH</button>
<button onClick={() => {
// state 안에 들어가 있을 경우 pop을 사용할 수 없으니 slice로 잘라서 원 배열에 마지막 요소만을 빼고 잘라버린다.
this.setState({
animal_ar: this.state.animal_ar.slice(0, this.state.animal_ar.length - 1)
})
}}>POP</button>
</div>
)
}
}
import React, { Component } from 'react'
import Sample from './190808_sample'
export default class App extends Component {
state = {
animal_ar : ['호랑이', '코끼리', '토끼'],
}
render() {
return (
<div>
<ol>{
this.state.animal_ar.map((v, k) =>
{
return <li onDoubleClick = {() => {
this.setState({
animal_ar: this.state.animal_ar.slice(0, k).concat(this.state.animal_ar.slice(k + 1, this.state.animal_ar.length))
})
}}
key = {k}>{v}</li>
})
}
</ol>
<button onClick={() => {
this.setState({
animal_ar: this.state.animal_ar.concat('독수리'),
})
}}>PUSH</button>
<button onClick={() => {
// state 안에 들어가 있을 경우 pop을 사용할 수 없으니 slice로 잘라서 원 배열에 마지막 요소만을 빼고 잘라버린다.
this.setState({
animal_ar: this.state.animal_ar.slice(0, this.state.animal_ar.length - 1)
})
}}>POP</button>
</div>
)
}
}
<ol>{
this.state.animal_ar.map((v, k) =>
{
return <li onDoubleClick = {() => {
let arr = [
...this.state.animal_ar.slice(0, k),
...this.state.animal_ar.slice(k + 1, this.state.animal_ar.length)
]
this.setState({
animal_ar: arr
})
}}
key = {k}>{v}</li>
})
}
</ol>
import React, { Component } from 'react'
import Sample from './190808_sample'
export default class App extends Component {
state = {
ar : ['호랑이', '코끼리', '토끼'],
}
render() {
//* this.state.ar을 'ar'로 치환
// const ar = this.state.ar
//* 비구조화 할당을 사용
const {ar} = this.state
//TODO 위 두 예문은 같은 기능을 함
return (
<div>
<ol>{
ar.map((v, k) =>
{
return <li onDoubleClick = {() => {
// 전개연산자로 붙임
let arr = [
...ar.slice(0, k),
...ar.slice(k + 1, ar.length)
]
this.setState({
animal_ar: arr
})
}}
key = {k}>{v}</li>
})
}
</ol>
<button onClick={() => {
this.setState({
animal_ar: ar.concat('독수리'),
})
}}>PUSH</button>
<button onClick={() => {
// state 안에 들어가 있을 경우 pop을 사용할 수 없으니 slice로 잘라서 원 배열에 마지막 요소만을 빼고 잘라버린다.
this.setState({
animal_ar: ar.slice(0, ar.length - 1)
})
}}>POP</button>
</div>
)
}
}
import React, { Component } from 'react'
import Sample from './190808_sample'
export default class App extends Component {
render() {
return (
<div>
<Bpp a = '호랑이' b = {10}/>
</div>
)
}
}
// 함수형 컴포넌트 예제
// Bpp = (props)로 받아서 this.props로 받을 필요 없이, 안에 {a, b}를 넣어서 바로 a, b로 사용함.
const Bpp = ({a, b}) => {
return (
<div>
<h1>Bpp</h1>
<h2>{a}</h2>
<h2>{b}</h2>
</div>
);
실습 #2
- Props와 State의 차이점
- 크게
값을 갱신할수 있냐, 없냐
로 구분한다.- Props
- 값을 단순히 받아오고, 값 갱신이 불가능.
- State
- 컴포넌트 자체에서 초기화 하며, 값 갱신이 가능하다.
- 단독으로 값 갱신은 불가능 하며, 함수를 사용해아하는데
setState()
라는 함수를 사용한다
- 단독으로 값 갱신은 불가능 하며, 함수를 사용해아하는데
- 컴포넌트 자체에서 초기화 하며, 값 갱신이 가능하다.
- Props
- 꼭 State를 사용해야 하는 이유가 있는가?
- 일반 필드명으로도 선언이 가능하고, 값도 갱신이 가능하다. 하지만…
setState
로 값 갱신시 render()함수가 호출되어 화면상에 즉각적으로 렌더링이 가능하다. 하지만일반 필드명
으로 값을 갱신시, render()함수를 가지고 오지 않아, 즉각적으로 렌더링이 되지 않고 ‘값’만 변경된다.setState
는
- SetState는 비동기 함수이다
- 대신 다음 render() 전까지는 갱신이 된다는것을 보장한다.
- (ex) setState 안에서 갱신시킨 n1을
console.log()
로 출력할 경우 값이 갱신되지 않은 상태로 보임
- 정리
- 컨트롤 안에 값이 갱신되는 함수(화면에 보여야 하는 데이터)는 모두 state를 사용하자
- 화면에 보이는것과 관계없이 컴포넌트와 관계없이 내부적으로만 사용하는 변수는 필드로 사용해도 무방
import React, { Component } from 'react';
class EventPractice extends Component {
state = {
username: '',
email: '',
message: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleClick = () => {
alert(this.state.username + ': ' + this.state.message);
this.setState({
username: '',
message: ''
});
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleClick();
}
}
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="유저명"
value={this.state.username}
onChange={this.handleChange}
/>
<input
type="text"
name="message"
placeholder="아무거나 입력해보세요"
value={this.state.message}
onChange={this.handleChange}
onKeyPress={this.handleKeyPress}
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
}
}
export default EventPractice;
예시 #3-1
let n = 'a'
let obj = {
[n]: 0, // []이걸 a라고해줌
b: 10,
c: 20,
}
console.log(obj);
실습 #4-1
let ar = [10, 20, 30, 40, 50]
console.log(ar);
// map을 사용해 가공된 데이터 저장이 가능하다.
let br = ar.map((n) => {
console.log(n)
return n * 10
})
// value값과 함께 key값도 받아올 수 있다.
let cr = ar.map((n, key) => {
console.log(n, key)
return n * 10
})
console.log(br);
import React, { Component } from 'react'
export default class App extends Component {
// 알림창 띄우는 3개
f1 = () => {
// 알림창
alert("안녕하세요")
}
f2 = () => {
// 입력가능한 알림창
// 입력 결과값이 리턴된다. (취소시 null)
let result = prompt("안녕하세요", "입력하세요")
console.log(result);
}
f3 = () => {
// 확인,취소 알림창
// 입력 결과값이 리턴된다. (확인 true, 취소 false)
let result = window.confirm("정말 삭제하시겠습니까?")
console.log(result);
}
f4 = (e) => {
console.log("입력");
console.log(e.target.value);
}
f5 = (e) => {
this.setState({
txt : e.target.value
})
}
state = {
txt: "",
}
render() {
// 요사이는 this 필요없음
let ar = ['호랑이', '코끼리', '독수리']
let br = ar.map((v, k) => {
console.log(v, k);
// version이 업데이트되어서 key값을 매핑해야함. 안그럼 오류.
return <li key={k}>{v}</li>
})
return (
<div>
<button onClick = {this.f1}>f1</button>
<button onClick = {this.f2}>f2</button>
<button onClick = {this.f3}>f3</button>
{/* 익명함수를 통하여 alert 호출 */}
<button onClick = {() => {alert("글쎄요..")}}>글쎄요 버튼</button>
<input
//객체의 속성이기 때문에 콤마(,)를 사용하지않음.
type = "Text"
name = "메세지"
placeholder = "값을 입력하세요!"
onChange = {this.f5}
// input 태그는 한줄로 죽 안쓰기 때문에 엔터
/>
<button onClick = {() => {alert(this.state.txt)}}>알람</button>
{br}
</div>
)
}
}
render() {
// 요사이는 this 필요없음
let ar = ['호랑이', '코끼리', '독수리']
let br = ar.map((v, k) => <li key={k}>{v}</li>)
// rcfc로 생성
import React, { Component } from 'react';
class App extends Component {
// Mount = 보조시스템을 꼽을때 사용 <=> Unmount
// render()되기 전에 값 갱신이 필요할때 사용
// 'will'은 어떤 작업을 하기 전에 일어남
componentWillMount() {
console.log(1);
}
// render() 된 후에 값 갱신이 필요할때 사용
// 'did'는 어떤 작업을 한 후에 일어남
componentDidMount() {
console.log(2);
}
componentWillReceiveProps(nextProps) {
console.log(3);
}
shouldComponentUpdate(nextProps, nextState) {
console.log(4);
}
componentWillUpdate(nextProps, nextState) {
console.log(5);
}
componentDidUpdate(prevProps, prevState) {
console.log(6);
}
componentWillUnmount() {
console.log(7);
}
render() {
console.log(8);
// 컴포넌트의 lifecycle
// 실행시 1, 8, 2가 나옴.
// 나머지 함수는 props로 넘어갈때 , 넘어가고나서 등의 상황에 사용
return (
<div>
</div>
);
}
}
App.propTypes = {
};
export default App;
import React, { Component } from 'react'
export default class App extends Component {
render() {
return (
<div>
<Bpp a='호랑이'/>
</div>
)
}
}
// 'state'를 사용할 일이 없다. => 함수형 컴포넌트
// 앞에 나왔던 7가지의 life cycle이 없어서 가볍다. => 함수형 컴포넌트
// 부모에게 props 받는건 가능 => 함수형 컴포넌트
// 2. 함수형 컴포넌트이며, rsc 단축키로 생성한다.
const Bpp = (t) => {
return (
<div>
<h1>Bpp</h1>
{t.a}
</div>
);
};
// 1. 함수형 컴포넌트
// function Com () {
// return (
// <div>
// <h1>COM</h1>
// <h1>{this.props.a}</h1>
// </div>
// )
// }
정리
- props와 state는 값의 갱신 가능 유무에 따라 갈린다.
- state와 일반 필드의 차이는 render() 함수를 불러오느냐에 따라 구분한다.
import* as...
를 사용하면 Component내의 function들만 불러온다.import ...
를 사용하면 default Component를 불러온다.import ..., {...}
를 사용하면 default Component를 포함해{}
안에 들어있는 Component도 함께 불러온다.- 내부에서만이 아닌 외부에서도 함수나 컴포넌트를 사용하려면 앞에
export
를 붙여 주어야 한다.
import React, { Component } from 'react'
import Sample from './190808_sample'
import { connect } from 'react-redux'
class App extends Component {
render() {
console.log(App);
return (
<div>
{/* <Bpp a = '호랑이' b = {10}/> */}
<h1>{this.props.num}</h1>
<h1>{this.props.age}</h1>
<button onClick = {this.props.onAgeClick}>에러 생성기</button>
</div>
)
}
}
//! Action
// 내가 버튼을 onClick을 사용하지 않고, onmyclick을 쓰겠다. 라고 정의를 하는것이 action이다.
// 액션이 실행되고 데이터
//! java에서의 이벤트와 동격이다.
// dispatch는 내장 함수임.
// 객체를 인자로 받음.
// dispatch type은 해당 Key값을 모두 대문자로 해서 넣는것이 일반적임.
// action에서 원하는 기능을 찾아갈 때 type을 통해 찾아간다.
// Action을 걸 떄 onMyClick으로 잡는부분을 설정하는 곳.
export const mapActionToProps = (dispatch) => {
console.log('Action');
return {
// 카멜 표기법
onMyClick: () => {
dispatch({
type: 'MYCLICK'
})
},
onAgeClick: () => {
dispatch({
type: 'AGECLICK'
})
}
}
}
// reduse는 람다로 안씀
// 주는놈은 프로듀서,받는쪽 리듀스. (hadoop에서 사용)
// state의 초기값을 reduce를 처음 실행했을때 설정을 해주어야 한다. - 현재 10으로 설정하였음.
export function reduce(state = {num: 10, age: 100}, action) {
// 매개변수에서 state를 받을때 사용할 변수의 초기값을 설정해주어야한다.
// reduce => setState 함수 코드와 같은 역할을 한다.
console.log('Reduce');
switch (action.type) {
//* 1. state의 모든 상태변화는 reduce에서 실행된다. (setState를 이용한 모든 갱신은 모두 여기서 일어난다.)
//* 2. reduce 함수는 반드시 순수함수여야 한다.
//* - 순수함수란? 함수로 전달된 인수 값을 변경시키지 않고 외부의 전역변수를 끌고와서 사용하지 않는 함수
//TODO =====================
case 'MYCLICK':
state = {
num: state.num + 1,
}
console.log(state.num);
console.log(action.type);
// 실질적으로 이 return문에서 setState가 일어난다. store에서 값이 변경되었다는걸 알리고 state가 해당 값을 받아온다.
case 'AGECLICK':
state = {
...state,
age: state.age + 1,
}
return state
//TODO =====================
// default 에서는 반드시 state를 걸어줘야한다.
default:
return state
}
}
// state가 지나면 컴포넌트로 돌아옴
// state의 값은 store에서 가져왔다. 라고 생각해도 무방.
const mapStateToProps = (state) => {
console.log('state');
return {
// 여기서 데이터 갱신(num = state.num + 1)을 하려하지마라. 데이터 갱신은 무조건 reduce에서.
// store에서 갱신시키고 싶은것은 reduce에서 해라. 여기는 store를 갱신시키는게 아니다.
// 데이터를 최종 가공하는 용도로 사용이 된다.
//* 실제 달러 <=> 원화 환산으로 사용하기가 좋다.
//* 실제 값은 `12`달러지만 *1000을 해주면 달러로 변환이 되어 `12000`원이 되듯이 나온다.
num: state.num,
age: state.age
}
}
// 함수형 컴포넌트 예제
// Bpp = (props)로 받아서 this.props로 받을 필요 없이, 안에 {a, b}를 넣어서 바로 a, b로 사용함.
const Bpp = ({a, b}) => {
return (
<div>
<h1>Bpp</h1>
<h2>{a}</h2>
<h2>{b}</h2>
</div>
);
};
const Cpp = ({a, b}) => {
return (
<div>
<h1>Bpp</h1>
<h2>{a}</h2>
<h2>{b}</h2>
</div>
);
};
export default connect(
mapStateToProps, mapActionToProps,
) (App);
import React, { Component } from 'react'
import { connect } from 'react-redux'
class App extends Component {
render() {
return (
<div>
<h1>{this.props.num}</h1>
<button onClick = {this.props.onAddClick}>증가 버튼</button>
<Dec />
</div>
)
}
}
//* Step 1
export const mapActionToProps = (dispatch) => {
console.log('Action');
return {
// 카멜 표기법
onAddClick: () => {
dispatch({
type: 'ADDCLICK'
})
},
onDecClick: () => {
dispatch({
type: 'DECCLICK'
})
}
}
}
//* Step 3
export function reduce(state = {num: 0}, action) {
console.log('Reduce');
switch (action.type) {
//TODO =====================
case 'ADDCLICK':
state = {
num: state.num + 1
}
console.log(state.num);
return state
case 'DECCLICK':
state = {
num: state.num - 1
}
console.log(state.num);
return state
//TODO =====================
default:
return state
}
}
//* Step 2
const mapStateToProps = (state) => {
console.log('state');
return {
num: state.num,
}
}
class Bpp extends Component {
render() {
return (
<div>
{/* Step 5 */}
<button onClick = {this.props.onDecClick}>감소 버튼</button>
</div>
);
}
}
//? 현재 컴포넌트에서 사용하는 일반적인 방법
export default connect(
mapStateToProps, mapActionToProps,
) (App);
//! 다른 컴포넌트에서 태그모양으로 받기 위해 정의
const Dec = connect(mapStateToProps, mapActionToProps,) (Bpp);
import React, { Component } from 'react'
import { connect } from 'react-redux'
class App extends Component {
render() {
return (
<div>
<h1>{this.props.num}</h1>
<button onClick = {this.props.onAddClick}>증가 버튼</button>
<Bpp />
</div>
)
}
}
//* Step 1
export const mapActionToProps = (dispatch) => {
return {
// 카멜 표기법
onAddClick: () => {
dispatch({
type: 'ADDCLICK'
})
},
onDecClick: () => {
dispatch({
type: 'DECCLICK'
})
}
}
}
//* Step 3
export function reduce(state = {num: 0}, action) {
switch (action.type) {
//TODO =====================
case 'ADDCLICK':
state = {
num: state.num + 1
}
return state
case 'DECCLICK':
state = {
num: state.num - 1
}
return state
//TODO =====================
default:
return state
}
}
//* Step 2
const mapStateToProps = (state) => {
return {
num: state.num,
}
}
class Bpp extends Component {
render() {
return (
<div>
<Ctx />
</div>
);
}
}
class Cpp extends Component {
render() {
return (
<div>
<button onClick = {this.props.onDecClick}>감소 버튼</button>
</div>
);
}
}
//? 현재 컴포넌트에서 사용하는 일반적인 방법
export default connect(
mapStateToProps, mapActionToProps,
) (App);
//! 다른 컴포넌트에서 태그모양으로 받기 위해 정의
const Ctx = connect(mapStateToProps, mapActionToProps,) (Cpp);
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Bpp extends Component {
render() {
return (
<div>
{/* //* Step 1 */}
<Ctn />
</div>
)
}
}
//* Step 2
//! redux : Action
export const mapActionToProps = (dispatch) => {
return {
// 카멜 표기법
onMyClick: () => {
dispatch({
type: 'MYCLICK'
})
},
}
}
//* Step 4는 reduce를 store에 등록하는것임. 지금은 등록되어있어 패스.
//* Step 3
//! redux : reduce
export function reducer(state = null, action, e) {
switch (action.type) {
case 'MYCLICK' :
console.log('in MyClick');
// return값에 state가 없으니 null로 사용해도 무방하다.
return state
default:
return state
}
}
const mapStateToProps = (state) => {
return {
}
}
class Com1 extends Component {
render() {
return (
<div>
{/* //* Step 1 */}
<button onClick = {this.props.onMyClick}>안녕 버튼</button>
</div>
);
}
}
//! 3가지를 모두 묶은것을 container라고 한다.
//* Ctn은 이제 태그처럼 사용된다. (첫글자는 대문자여야함)
const Ctn = connect(null, mapActionToProps,) (Com1);
export default Bpp;