ReactJS - #5 기초 및 실습 (1주차)
Class Component
[Class.js]
import React, { Component} from 'react'
// state 기능 및 라이프 사이클 기능을 사용
// render 함수가 반드시 필요(class형 Component에서)
class ClassComponent extends Component{
// 생성자 함수
// 생성자가 이유는 props나 state같은 상태값들을 초기화하기 위해서
constructor(props){
// constructor를 사용하면 항상 병용, this를 초기화, props를 넣어줘야 this.props 사용가능
// suepr(props)를 통해서 this를 초기화 해주지 않으면 다른 component에서 사용했던 this와 충돌이 발생할 가능성이 있다.
// super() 이렇게 props를 파라미터로 안주고도 할 수 있는데 그럼 props를 쓸 수가 없다.
super(props)
// initial state를 선언
// this.state = {} 이 과정을 통해 component내의 render 함수에서 key값에 접근할때 this.state.key가 아닌 key로 접근가능
this.state = {
key : 'initialValue'
}
// event binding
// this를 쓰기 위함이라고 생각하면 되는데 this에 묶여져 있는 event가 우리가 밑에 선언한 이벤트와 묶여서 바인딩이 된다 ?
// 흠.. 잘 이해가 안되는데 근데 이건 Class Component에만 존재하고 function Component에는 없다.
this.handleClick = this.handleClick.bind(this)
console.log('constructor')
}
static defaultProps = {
name : '홍길동'
}
handleClick(){
// event binding을 안시켜놓으면 여기에서 this가 state를 가리키지 않아서 오류가 발생한다.
this.setState({ key : 'value2'})
}
componentWillMount(){
console.log('componentWillMount') // DOM이 생성되지 않은 단계, setState 실행 x
}
componentDidMount(){
// 외부 데이터 가져오기
// this.setState({})
console.log('componentDidMount') // DOM이 생성된 단계, setState를 통해 DOM의 제어가 가능
}
componentWillReceiveProps(nextProps){
console.log('componentWillReceiveProps');
}
shouldComponentUpdate(nextProps, nextState){
console.log('shouldComponentUpdate');
return true;
}
componentDidUpdate(prevProps, prevState){
console.log('componentDidUpdate');
}
// componentDidCatch(){
// 에러 핸들링
//}
render(){
// render() 함수를 통해 props를 조회
// 비구조화 할당 방식으로 state와 props 사용 가능
const { key } = this.state;
const { name } = this.props;
console.log('render')
return(
<div>
<h1>클래스형 컴포넌트</h1>
<h2>{ key }</h2>
<h2>{ name }</h2>
<button onClick={this.handleClick}>클릭</button>
</div>
);
}
}
export default ClassComponent;
* 메소드에 대한 세부내용은 주석 참고
Function Component
import {useState, useEffect} from 'react';
// state 기능 및 라이프 사이클 기능을 사용할 수 없음 (stateless) 그래서 hook이 나오기전까지 class Component 사용 권장
// 리액트 버전 16.8부터 Hook이 등장 -> state, lifeCycle 기능 대체가능
// 클래스형 컴포넌트보다 간단
// 클래스형 컴포넌트보다 메모리 자원을 적게 사용
// -> 최근에는 function Component 사용 권장
// 비구조화 할당으로 props 사용 가능
const FuntionalComponet = (props) =>{
const [name, setName] = useState('홍길동');
// 설정한 state, setState({key : value}) -> setKey(value)의 구조
// useState('홍길동') -> initalize
const handleClickBtn = (val) => {
setName(val);
}
useEffect(() =>{
console.log('component did update');
// return () =>{
// console.log('component will mount');
// }
}, []);
// Class Component와 다르게 render()가 없고 return으로 바로 들어감
// return이라는 부분안에서 state같은 상태값들을 포함한 html 태그들을 사용하는게 JSX
return (
<div>
<h1>함수형 컴포넌트</h1>
<h2>{ name }</h2>
<button onClick ={()=>setName('김철수')}>변경</button>
{/* onClick={} 이안에 왜 에로우 펑션을 써야되나? */}
{/* () => handleClickBtn('김철순') */}
{/* handleClickBtn('김철순') */}
{/* 위 두개의 차이점이 무엇인가 봤을때 파라미터로 어떤 값을 던져줄경우 반드시 funtion의 형태로 만들어줘야 하기때문에 ()=> fution('val') 의 형태로 만들어주어야 하고 */}
{/* 파라미터가 없이 그냥 값을 가져오기만 하는 경우에는 handleClickBtn 까지 ()를 생략한 것을 onClick에 넣어주면 정상적으로 실행됨 */}
<button onClick ={()=>handleClickBtn('김철순')}>변경</button>
</div>
)
}
export default FuntionalComponet;
* 세부 내용은 주석 참고
위의 function Componet를 세부적인 Component로 쪼개 보자!
components 폴더를 만들고 그 안에 name.js 파일을 만든다.
[name.js]
[functional.js]
이렇게 구조를 나눠주면 각각 다른 파일의 js이지만 한페이지에서 바꾸는 것처럼 페이지가 동작한다.
또한, button의 onClick에서 실행되는 callback funtion은 functional의 state 즉, 상위 component의 state를 바꾸는
funciton을 수행하는데, 이 상위의 component의 state를 바꾸는 것만으로도 하위의 Component에서 영향을 받아
자동으로 수정되는 구조를 가진다.!!
주의해야 할 건 name.js에서 사용하는 props.name 같은 props는 수정할 수 없다는 점!
props의 값을 바꾸려면 부모 Component의 state를 수정해서 자식 Component가 받는 props의 값을 수정해야하는
구조를 반드시 이해해야한다.
[name.js]
const NameComp = (props) => {
const handelClickBtn = (val) =>{
props.onClickCB(val)
}
return (
<div>
<h2>
{props.name}
</h2>
<button onClick={()=>handelClickBtn('하위 컴포넌트')}>변경</button>
</div>
);
}
export default NameComp;
[functional.js]
return (
<div>
<h1>함수형 컴포넌트</h1>
{/* <h2>{ name } </h2> */}
<Name name={ name }
onClickCB={handleClickBtn}/>
<button onClick ={()=>setName('김철수')}>변경</button>
{/* onClick={} 이안에 왜 에로우 펑션을 써야되나? */}
{/* () => handleClickBtn('김철순') */}
{/* handleClickBtn('김철순') */}
{/* 위 두개의 차이점이 무엇인가 봤을때 파라미터로 어떤 값을 던져줄경우 반드시 funtion의 형태로 만들어줘야 하기때문에 ()=> fution('val') 의 형태로 만들어주어야 하고 */}
{/* 파라미터가 없이 그냥 값을 가져오기만 하는 경우에는 handleClickBtn 까지 ()를 생략한 것을 onClick에 넣어주면 정상적으로 실행됨 */}
<button onClick ={()=>handleClickBtn('김철순')}>변경</button>
</div>
)
이런식으로 상위 Component의 handleClickBtn이란 메소드를 하위 Component에 전달해서 하위 컴포넌트의 버튼을
클릭하면 상위 Component의 state를 수정하는 메소드가 작동하게 하는 구조!!
자 여기서 한번 정리해보자
react hook을 쓰려면 이렇게 import해주어야 되고
import { useState } from 'react';
하위 컴포넌트들을 사용하려면 상위 컴포넌트에서 import 해야하는데
import Name from '../components/name';
import Job from '../components/job';
이렇게 import해주면 되는데 Component를 import 하기전에 필수적으로 선행되어야 하는 순서는
각각의 하위 component에서 export default를 선언해주어야 한다는 것이다.
export default JobComp;
또한 hook을 사용하는 구조는
이런식으로 사용하게 되고 배열의 첫번째 인덱스에는 값이 저장될 장소, 두번째 인덱스는 저장된 값을 컨트롤하는 메소드이다.
또한
상위 컴포넌트에서 import한 하위컴포넌트를 사용할 때는 <Name /> 이런 형태로 사용하며
값을 직접 던져줄 수 있다.
그럼 이렇게 상위 component에서 던져준 job과 onClickCB를 props로 받게 되는데
밑의 코드에서는 비 구조 할당 방식으로 필요한 값들을 할당해서 사용하였다
또한 JSX에서는 html문과 함께 script 문도 사용할 수 있기 때문에 { } 안에서 아래와 같이 삼항연산자 따위의 script 문법들을
사용할 수 있다.!!