Class Component 작성법
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
console.log(React)
console.log(ReactDOM)
//ClassComponent 정의하기
class ClassComponent extends React.Component{ //React안에 Component라는 클래스를 상속 받음
render(){ //render 메서드는 정의 되어야하고 return 값이 꼭 있어야 함
return <div>Hello</div>;
}
}
//ClassComponent 사용하기
ReactDOM.render(
<ClassComponent />,
document.querySelector('#root')
)
</script>
</body>
</html>
- 위와 같이 작성하면 Class Component를 사용할 수 있다.
Class Component 정의하기
class ClassComponent extends React.Component{ //React안에 Component라는 클래스를 상속 받음
render(){ //render 메서드는 정의 되어야하고 return 값이 꼭 있어야 함
return <div>Hello</div>;
}
}
- ClassComponent라는 이름의 클래스 컴포넌트를 React 라이브러리 안에 있는 Component 클래스로부터 상속받았다.
- Component 클래스 안에는 render() 메서드 값이 필요하며 render 값에는 꼭 return 값이 있어야 한다.
Class Component 사용하기
ReactDOM.render(
<ClassComponent />,
document.querySelector('#root')
)
- ReactDom의 render 메서드를 이용하여 출력한다.
- 첫 번째 인자는 만들어 두었던 Component를 가져오고, 두 번째 인자는 어떤 html에 넣을지 css 쿼리 실렉터로 넣어준 모습이다.
Function Component 작성법
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
console.log(React)
console.log(ReactDOM)
//Function Component 정의 1
function FunctionComponent(){
return <div>Hellos</div>;
}
//Function Component 정의 2
const FunctionComponent = ()=><div>Hello</div>;
//Function Component 사용
ReactDOM.render(
<FunctionComponent />,
document.querySelector('#root')
)
</script>
</body>
</html>
- 위와 같이 작성하면 Class Component를 사용할 수 있다.
function Component 정의하기
//Function Component 정의 1
function FunctionComponent(){
return <div>Hellos</div>;
}
//Function Component 정의 2
const FunctionComponent = ()=><div>Hello</div>;
- 리액트 라이브러리에서 상속받는 것이 아닌 순수한 함수이다.
- function component 또한 return 값이 필수로 존재해야 하며 JSX로 들어가야 한다.
- 인자는 있어도 되고 없어도 된다.
- JS에서 function은 2가지 방법으로 만들 수 있기 때문에 두 가지 다 사용 가능하다.
Function Component 사용하기
ReactDOM.render(
<FunctionComponent />,
document.querySelector('#root')
)
- ReactDom의 render 메서드를 이용하여 출력한다.
- 첫 번째 인자는 만들어 두었던 Component를 가져오고, 두 번째 인자는 어떤 html에 넣을지 css 쿼리 실렉터로 넣어준 모습이다.
React.createElement로 컴포넌트 만들기
React.createElement(
type, //태그 이름 문자열 | 기존에 만든 리액트 컴포넌트 | React.Fragment
[props], //리액트 컴포넌트에 넣어주는 데이터 객체
[...children] //자식으로 넣어주는 요소들
)
- createElement는 총 3가지 방법으로 제작 가능하다.
1. 태그 이름 문자열 type
// 1. 태그 이름 문자열 type
ReactDOM.render(
React.createElement('h1', null, `type 이 "태그 이름 문자열" 입니다.`), //component 뿐만 아니라 create Element도 허용
document.querySelector('#root')
)
- <h1>`createElement 메서드 안에 3번째 인자의 내용이 들어감`</h1> 이 태그로 그려진다.
2. 리액트 컴포넌트 type
//2. 리액트 컴포넌트 type
const Component = () =>React.createElement('h1', null, `type 이 "React 컴포넌트" 입니다.`)
ReactDOM.render(
React.createElement(Component, null, null),
document.querySelector('#root')
)
- <Component></Component> 컴포넌트로 그려진다.
3. React.Fragment type
//3. React.Fragment
ReactDOM.render(
React.createElement(
React.Fragment,
null,
`type 이 "React Fragment" 입니다.`
),
document.querySelector('#root')
)
- 다음 사진과 같이 React.Fragment를 사용하면 다른 태그 없이 <div id=root> 안에 바로 나타나게 된다.
JSX
- 우리가 작성한 코드를 순수하게 실행 가능 한 자바 스크립트로 만들어주는 것은 babel이다.
- 더 나아가 설명하면 es6를 지원하지 않는 브라우저에게 es 6 문법들을 사용할 수 있게 자동으로 변환시켜주는 것을 의미한다. (컴파일 또는 트랜스 파일)
- babeljs.io
- babel은 우리가 React.createElement를 직접 작성하지 않아도 다음과 같이 트랜스 파일 해준다.
<script type="text/babel">
console.log(React)
console.log(ReactDOM)
//복잡한 리액트 엘리먼트들의 모임
ReactDOM.render(
<div a ="a">
<h1>주제</h1>
<ul>
<li>React</li>
<li>Vue</li>
</ul>
</div>,
document.querySelector('#root')
)
</script>
- React.createElement VS. JSX일 때 가독성으로 JSX가 훨씬 좋다
- babel과 같은 컴파일 과정에서 문법 오류를 인지하기 쉽다. 일반 html보다 babel을 통한 JSX는 문법 오류를 잘 잡는다.
JSX 문법 알아보기
- 최상위 요소가 하나여야 한다.
- 최상위 요소를 리턴하는 경우, ()로 감싸야한다.
- 자식들을 바로 렌더링 하고 싶으면, <> 자식들 </>를 사용한다. 이런 걸 Fragment라고 부른다.
- 자바스크립트 표현식을 중간에 사용하려면, { JS }를 이용하여야 한다.
- if문은 사용할 수 없다. 삼항 연산자를 이용하여야 한다.
- style을 이용해 인라인 스타일링이 가능하다.
- class 대신 className을 사용하여야 제대로 된 class 적용이 가능하다.
- 자식 요소가 있으면, 꼭 닫아야 하고, 자식 요소가 없으면 열면서 닫아야 한다.
- <p> ~~~ </p>
- <br />
Props와 State
- Props는 컴포넌트 외부에서 컴포넌트에게 주는 데이터를 뜻한다.
- State는 컴포넌트 내부에서 변경할 수 있는 데이터를 뜻한다.
- 각각 변경이 발생하면 재랜더 될 수 있다. (랜더 함수 실행)
- 각각 class와 function으로 props를 사용한 component들이다.
// {message: '안녕하세요''} 메세지의 값이 바뀌면 재랜더가 일어나게 된다.
function Component(props){ //function 컴포넌트는 인자로 props가 들어오게 된다.
return <div><h1>{props.message} 함수로 만든 컴포넌트 입니다.</h1></div>
}
ReactDOM.render(<Component message ="안녕하세요"/>, document.querySelector("#root"))
// {message: '안녕하세요''} 메세지의 값이 바뀌면 재랜더가 일어나게 된다.
class Component extends React.Component{
render(){
return(
<div>
<h1>{this.props.message} 클래스로 만든 컴포넌트 입니다</h1>
</div>
)
}
}
ReactDOM.render(<Component message ="안녕하세요"/>, document.querySelector("#root"))
다음과 같이 class Component는 props를 사용할 때 this를 사용하여야 한다.
- 만약 message 값이 존재하지 않을 때 기본 값을 설정하려고 한다면 다음 방법을 이용하면 된다.
Component.defaultProps = {
message: "기본값",
}
- 또는 class 안에선 static defaultProps를 통해 기본 값을 지정할 수 있다.
class Component extends React.Component{
render(){
return(
<div>
<h1>{this.props.message} 클래스로 만든 컴포넌트 입니다</h1>
</div>
)
}
static defaultProps = {
message: "기본값",
}
}
State 사용하기
class Component extends React.Component{
state = { //state는 항상 객체여야 한다.
count: 0,
};
render(){
return(
<div>
<h1>{this.props.message} 클래스로 만든 컴포넌트 입니다</h1>
<p>{this.state.count}</p>
</div>
)
}
componentDidMount(){
setTimeout(() =>{
//this.state.count = this.state.count + 1과 같은 의미의 코드이다.
this.setState({
count: this.state.count + 1
});
}, 1000)
}
ReactDOM.render(<Component message ="안녕하세요"/>, document.querySelector("#root"))
- 원래의 state 생성 방식은 다음과 같다.
//state = { //state는 항상 객체여야 한다.
// count: 0,
//};
constructor(props){
super(props);
this.state = {count: 0 };
}
- 또한 this.setState도 다른 방식으로 작성이 가능하다.
this.setState({
count: this.state.count + 1
});
this.setState((previousState) => {
const newState = { count: previousState.count + 1 };
return newState;
)};
Event Handling이란?
- HTML DOM에 클릭하면 이벤트가 발생하고, 발생하면 그에 맞는 변경이 일어나도록 해야 한다.
- camelCase로만 사용할 수 있다.
- onClick, onMouseEnter
- 이벤트에 연결된 자바스크립트는 함수이다.
- 이벤트 = {함수}와 같이 사용한다.
- 실제 DOM 요소들에만 사용 가능하다.
- 리액트 컴포넌트에 사용하면 그냥 props로 전달한다.
function Component() {
return (<div>
<button
onClick={() => { // 다음과 같이 onClick 사용
console.log("clicked");
}}>
클릭
</button>
</div>);
}
ReactDOM.render(<Component/>, document.querySelector("#root"))
- 다음은 state를 사용하여 이벤트가 발생했을 때 숫자가 올라가는 코드입니다.
class Component extends React.Component {
state = {
count: 0,
};
render() {
return (<div>
<p>{this.state.count}</p>
<button
onClick={() => {
this.setState((state) => ({ ...state, count: state.count + 1, }))
}}>
클릭
</button>
</div>);
}
}
ReactDOM.render(<Component />, document.querySelector("#root"))
- 이렇게 따로 메서드를 분리하여서 코드 작성도 가능합니다.
class Component extends React.Component {
state = {
count: 0,
};
render() {
return (<div>
<p>{this.state.count}</p>
<button
onClick={click}>
클릭
</button>
</div>);
}
click = () => {
this.setState((state) => ({ ...state, count: state.count + 1, }))
}
}
ReactDOM.render(<Component />, document.querySelector("#root"))
Component LifeCycle이란?
- 리액트 컴포넌트는 브라우저에 그려져서 사라질 때까지 여러 지점에서 개발자가 작업이 가능하도록 메서드를 오버 라이딩할 수 있게 해 준다.
- Initialization은 constructor 부분을 의미한다. 즉 props가 설정되고 state 또한 설정된다.
- mounting 단계에서 render 작업을 한다. 이때 브라우저에 그려지게 된다.
- Unmounting은 사라지기 전 단계를 의미한다.
- 그 외 나머지들은 props와 state가 변경되어 렌더 메서드가 실행될 때 실행되는 메서드들이다.
현재 리액트 버전을 기준으로 하는 것이 아닌 16.3 버전 이전의 life Cycle을 설명한다.
Component 생성 (mount)
class App extends React.Component {
state = {
age:39,
}
constructor(props){
super(props);
console.log('constructor', props);
}
render(){
console.log('render'); // 렌더 될 때 마다 로그가 찍힘
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
</div>
);
}
componentWillMount() {
console.log('componentWillMount')
}
componentDidMount() {
console.log('componentDidMount')
//보통 타이머나 API 요청하는 곳
setInterval(()=>{this.setState((state)=>({ age:state.age+1}))},1000)
}
}
ReactDOM.render(<App name = "mark" />, document.querySelector("#root"))
- 위 코드는 다음과 같은 순서로 로그가 찍힐 것이다.
- constructor (생성) -> componentWillMount -> render -> componentDidMount -> 재랜더 (반복)
- Warning이 뜨는 이유는 상위 버전에서는 사라진 component life cycle들이 있기에 duplicated 될 위험이 있음을 알리는 것이다.
Component props, state의 변경
componentWillReceiceProps(nextProps){
console.log("componentWillReceiveProps", nextProps);
}
shouldComponentUpdate(nextProps, nextState){
console.log('shouldComponentUpdate', nextProps, nextState);
return true;
}
componentWillUpdate(nextProps, nextState){
console.log('componentWillUpdate',nextProps, nextState);
}
componentDidUpdate(prevProps, prevState){
console.log('componentWillUpdate',prevProps, prevState);
//렌더가 발생한 후이니 previous props와 prevState를 가지게 된다.
}
- 로그 찍히는 순서를 잘 보고, prevProps와 nextProps를 잘 확인하도록 하자.
- ComponentWillReceiveProps
- props를 새로 지정했을 때 바로 호출된다.
- 여기는 state의 변경에 반응하지 않는다.
- 여기서 props의 값에 따라 state를 변경해야 한다면, setState를 통해 state를 변경합니다. 그러면 다음 이벤트로 각각 가는 것이 아니라 한 번에 변경된다..
- shouldComponentUpdate
- props만 변경되어도 되고 state만 변경되어도 되고 둘 다 변경되어도 발생한다.
- newProps와 newState를 인자로 해서 호출한다.
- return 타입이 bool형식이다.
- true면 render 함수를 호출하고,
- false면 render 함수를 호출하지 않기 때문에 재 랜더링 되지 않는다.
- 이 함수를 구현하지 않는다면 default 값은 true이다.
- componentWillUpdate
- 컴포넌트가 재 랜더링 되기 직전에 호출된다.
- 여기선 setState 같은 것들을 사용하면 안 된다.
- componentDidUpdate
- 컴포넌트가 재 랜더링 되고 난 후 불린다.
Component unmount
componentWillUnmount(){
clearInterval(this.interval)
}
- 사용하고 있는 API의 호출을 끊어주거나 불필요한 메모리 제거를 위해 사용한다. (ex. clearInterval)
React 16.3 버전 이후의 라이프 사이클을 알아보자.
- constructor
componentWillMount-> getDerivedStateFromProps- render
- componentDidMount
ComponentWillReceiveProps-> getDerivedStateFromProps- shouldComponentUpdate
componentWillUpdate-> getSnapshotBeforeUpdate- componentWillUpdate
- componentDidUpdate
getDerivedStateFromProps
// componentWillMount() {
// console.log('componentWillMount')
//}
static getDerivedStateFromProps(nextProps, previousState){
console.log('getDerivedStateFromProps', nextProps, previousState)
return null;
}
- 리턴 값에는 state가 들어온다.
- 드문 경우에 사용 되게 변경되었다.
let i = 0
class App extends React.Component{
state = {
list:[]
}
render(){
return(
<div id="list" style={{height: 100, overflow:"scroll"}}>
{this.state.list.map( i =>{
return <div>{i}</div>;
})}
</div>
)
}
componentDidMount(){
setInterval(()=>{
this.setState(state => ({
list: [...state.list, i++]
}))
}, 1000);
}
getSnapshotBeforeUpdate(prevProps, prevState){
if(prevState.list.length == this.state.list.length) return null;
const list = document.querySelector('#list');
return list.scrollHeight - list.scrollTop;
}
componentDidUpdate(prevProps, prevState, snapshot){
console.log(snapshot)
}
컴포넌트 에러 캐치하는 방법 componentDidCatch
class App extends React.Component{
state = {
hasError: false
};
render(){
if(this.state.hasError){
return <div>예상치 못한 에러 발생</div>
}
return <WebService/>;
}
componentDidCatch(error, information){
this.setState({hasError : true});
}
}
레퍼런스
'프론트엔드 개발 > React' 카테고리의 다른 글
[React] Router - JSX로 라우팅 이동하기 (0) | 2022.07.05 |
---|---|
[React] Dynamic Routing (0) | 2022.07.05 |
[React] SPA Router (0) | 2022.07.05 |
[React] SSR vs. CSR (Feat.Next.js) (0) | 2022.07.01 |
[React] BootStrap vs React-BootStrap (0) | 2022.04.29 |