01. 리액트가 만들어진 배경
- 처리해야 할 이벤트, 상태값, DOM이 다양해질때 코드가 복잡해지는 것을 해결하기 위함
- 어떠한 상태가 바뀔 때, 업데이트를 작업하는것이 아닌 모든걸 새로 만든다는 발상에서 출발
- Virtual DOM을 통해 실현 (업데이트에 대한 고민해결 + 빠른 성능)
01-1 Virtual DOM
- 브라우저에 실제로 보여지지 않는 가상의 DOM
- 업데이트가 필요한 곳의 UI를 Virtual DOM 을 통해서 렌더링
- 실제 브라우저에 보여지고 있는 DOM 과 비교를 한 후, 차이가 있는 곳을 감지하여 이를 실제 DOM 에 패치
02. 작업환경 준비
- Node.js : 자바스크립트 런타임 (Webpack, Babel 등의 도구들을 사용하기위해 설치)
- Yarn : 개선된 버전의 npm (라이브러리 설치 및 해당 라이브러리들의 버전 관리를 하게 될 때 사용)
- 코드 에디터 : VSCode, Atom, WebStorm, Sublime 등등
02-1 새 프로젝트 만들기
1) begin-react 디렉터리 안에 리액트 프로젝트 생성
$ npx create-react-app begin-react
2) begin-react 디렉터리에서 yarn start 명령어 입력
$ cd begin-react
$ yarn start
3. http://localhost:3000/ 브라우저 열림
※ Git Bash 에서의 기본 경로 : pwd명령어를 통해 확인
이외의 명령어 https://taei1.tistory.com/4 참고
03. 나의 첫번째 리액트 컴포넌트
- 리액트 컴포넌트는 함수형태, 클래스형태 모두 작성 가능
1) src 디렉터리에 Hello.js 파일 작성
//Hello.js
import React from 'react';
const Hello = () => {
return <div>안녕하세요</div>;
}
export default Hello; //Hello라는 컴포넌트를 내보내겠다는 의미(다른 컴포넌트를 불러와 사용 가능)
2) 리액트 호출
import React from 'react';
3) App.js에서 Hello 컴포넌트 불러오기
(Hello 컴포넌트를 div안에서 여러번 재사용 가능)
//App.js
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<div>
<Hello />
</div>
);
}
export default App;
4) Index.js 코드 살펴보기
- root.render : 실제 DOM 내부에 리액트 컴포넌트를 렌더링
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
<!-- public폴더 안 index.html 내부 -->
<div id="root"></div>
Index.js에서 렌더링 된 결과물이 index.html의 div 내부에 렌더링 됨
04. JSX
- 리액트에서 생김새를 정의할 때 사용하는 문법
- HTML의 모습을 하고 있지만 실제로는 JavaScript임
04-1 Babel
- 자바스크립트의 문법을 확장해주는 도구
- 리액트 컴포넌트 파일에서 XML 형태로 코드를 작성하면 babel 이 JSX 를 JavaScript 로 변환
04-2 JSX가 JavaScript로 변환하기 위한 규칙
1) 태그가 닫혀야 함
- 아래 코드는 태그를 닫는 </div>가 부족하므로 오류가 뜸
- Self Closing 태그 : 열리고 바로 닫히는 태그를 의미 ( ex. <Hello />)
//App.js
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<div>
<Hello />
<Hello />
<Hello />
<div>
</div>
);
}
export default App;
2) 태그가 감싸져야 함
- 두개 이상의 태그는 무조건 하나의 태그로 감싸져있어야 함
- 아래 코드는 Hello태그와 div태그를 다른 태그로 감싸주어야 오류 해결
※ 불필요한 태그를 만들어 감싸는 것은 비효율 --> 리액트의 Fragment (태그를 이름없이 작성) 사용
(Fragment : 브라우저 상에서 별도의 엘리먼트로 나타나지 않음 (작성예시. <> </>) )
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<Hello />
<div>안녕히계세요.</div>
);
}
export default App;
04-3 JSX안에 자바스크립트 값 사용하기
- JSX 내부에 자바스크립트 변수를 보여줄 때 {}로 감싸서 표현
import React from 'react';
import Hello from './Hello';
const = App() => {
const name = 'react';
return (
<>
<Hello />
<div>{name}</div>
</>
);
}
export default App;
04-4 style과 className
1) style 설정 방법
- 인라인 스타일 : 객체 형태로 작성, camelCase형태로 네이밍
import React from 'react';
import Hello from './Hello';
const App = () => {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
<Hello />
<div style={style}>{name}</div>
</>
);
}
export default App;
2) className 설정 방법
- class= 이 아닌 className= 으로 설정 해주어야 함
- 첫번째 css파일을 두번째 js파일에서 className="gray-box"로 불러옴
.gray-box {
background: gray;
width: 64px;
height: 64px;
}
import React from 'react';
import Hello from './Hello';
import './App.css';
const App = () => {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
<Hello />
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
04-5 주석
- 내부의 주석 : {/* 이런 형태로 */} 작성
- 태그 내부에서는 // 형태로도 주석 작성이 가능
import React from 'react';
import Hello from './Hello';
import './App.css';
const App = () => {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
{/* 주석은 화면에 보이지 않습니다 */}
/* 중괄호로 감싸지 않으면 화면에 보입니다 */
<Hello
// 열리는 태그 내부에서는 이렇게 주석을 작성 할 수 있습니다.
/>
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
05. props를 통해 컴포넌트에게 값 전달하기
- props : 어떠한 값을 컴포넌트에게 전달해야 할때 사용 (properties의 줄임말)
05-1 props 기본 사용법
1) App 컴포넌트에서 Hello 컴포넌트 사용할 때 name이라는 값 전달하기
//App.js
import React from 'react';
import Hello from './Hello';
function App() {
return (
<Hello name="react" />
);
}
export default App;
2) Hello 컴포넌트에서 name값 사용하기
- 파라미터를 통해 조회 가능
- 객체 형태로 전달
- props.name을 통해 name값 조회 가능
//Hello.js
import React from 'react';
const Hello = (props) => {
return <div>안녕하세요 {props.name}</div>
}
export default Hello;
05-2 여러개의 props, 비구조화 할당
1) color라는 값 전달
//App.js
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<Hello name="react" color="red"/>
);
}
export default App;
2) Hello 컴포넌트에서 color값 조회, 폰트의 색상으로 설정
//Hello.js
import React from 'react';
const Hello = (props) => {
return <div style={{ color: props.color }}>안녕하세요 {props.name}</div>
}
export default Hello;
3) 비구조화 할당 문법을 사용하여 코드 수정
- props. 대신에 파라미터에서 props 내부의 값 조회
import React from 'react';
const Hello = ({ color, name }) => {
return <div style={{ color }}>안녕하세요 {name}</div>
}
export default Hello;
05-3 defaultProps로 기본값 설정
- props를 지정하지 않고 기본적으로 사용할 값을 설정하고 싶을 때 사용
//Hello.js
import React from 'react';
function Hello({ color, name }) {
return <div style={{ color }}>안녕하세요 {name}</div>
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
- name이 없는 Hello 컴포넌트 렌더링
//App.js
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<>
<Hello name="react" color="red"/>
<Hello color="pink"/>
</>
);
}
export default App;
05-4 props.children
- 컴포넌트 태그 사이에 넣은 값을 조회할 때 사용
1) src 디렉터리에 Wrapper.js 생성
//Wrapper.js
import React from 'react';
const Wrapper = () => {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
</div>
)
}
export default Wrapper;
2) Wrapper 컴포넌트 App에서 사용
- Wrapper태그 내부에 Hello 컴포넌트를 넣음
//App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
function App() {
return (
<Wrapper>
<Hello name="react" color="red"/>
<Hello color="pink"/>
</Wrapper>
);
}
export default App;
- Hello 컴포넌트들이 보여지지 않음 --> Wrapper에서 props.chidren 렌더링 필요
- props.children 렌더링
//Wrapper.js
import React from 'react';
function Wrapper({ children }) {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
{children}
</div>
)
}
export default Wrapper;
- 결과물
06. 조건부 렌더링
- 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미
1) App 컴포넌트에서 Hello 컴포넌트를 사용할 때 isSpecial 이라는 props설정
//App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
const App = () => {
return (
<Wrapper>
<Hello name="react" color="red" isSpecial={true}/>
<Hello color="pink" />
</Wrapper>
)
}
export default App;
2) Hello 컴포넌트에서 isSpcial이 true 일때 <b>*</b> 를, 그렇지 않다면 null 을 보여주도록 작성 (삼항연산자 사용)
//Hello.js
import React from 'react';
const Hello = ({ color, name, isSpecial }) => {
return (
<div style={{ color }}>
{ isSpecial ? <b>*</b> : null }
안녕하세요 {name}
</div>
);
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
06-1 && 연산자
- 특정 조건이 true이면 보여주고, 그렇지 않다면 false (단축 평가 논리 계산법 학습 필요)
<div style={{ color }}>
{isSpecial && <b>*</b>}
안녕하세요 {name}
</div>
06-2 props값 설정을 생략하면 = {true}
- props 이름만 작성하고 값 설정을 생략하면 true로 설정한 것으로 간주
- 아래 코드에서는 isSpecial = {true}와 동일
<Wrapper>
<Hello name="react" color="red" isSpecial />
<Hello color="pink"/>
</Wrapper>
07. useState를 통해 컴포넌트에서 바뀌는 값 관리하기
- 사용자에 인터랙션에 따라 내용이 바뀌는 것을 구현해야 함
1) src 디렉터리에 Counter.js 코드 작성
//Counter.js
import React from 'react';
const Counter = () => {
return (
<div>
<h1>0</h1>
<button>+1</button>
<button>-1</button>
</div>
);
}
export default Counter;
2) App에서 Counter 렌더링
//App.js
import React from 'react';
import Counter from './Counter';
function App() {
return (
<Counter />
);
}
export default App;
3) 이벤트 설정 (Counter.js 수정)
- 클릭 이벤트가 발생 했을 때 특정 함수가 호출되도록 설정
- button에 onClick으로 각 함수를 연결
import React from 'react';
const Counter = () => {
const onIncrease = () => {
console.log('+1')
}
const onDecrease = () => {
console.log('-1');
}
return (
<div>
<h1>0</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
※리액트에서 엘리먼트에 이벤트를 설정해 줄때 on이벤트이름={실행하고싶은함수} 형태로 설정해야함
4) 동적인 값 끼얹기, useState
- 상태(state) : 컴포넌트에서 동적인 값을 의미
- useState함수 : 컴포넌트에서 상태를 관리할 수 있음
//Counter.js
import React, { useState } from 'react'; //리액트 패키지에서 useState 함수 호출
const Counter = () => {
const [number, setNumber] = useState(0); //상태의 기본값을 파라미터에 넣어 호출
// 첫번째 원소는 현재 상태, 두번째 원소는 Setter함수
const onIncrease = () => {
setNumber(number + 1);
}
const onDecrease = () => {
setNumber(number - 1); //배열 비구조화 할당을 통해 각 원소 추출
}
return (
<div>
<h1>{number}</h1> //0이 아닌 number값을 보여줌
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
5) 함수형 업데이트
- Setter함수를 사용할 때 새로운 값을 파라미터로 넣어주는 대신, 기존값을 함수를 등록하는 방식으로 업데이트 가능
//Counter.js
import React, { useState } from 'react';
const Counter = () => {
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(prevNumber => prevNumber + 1);
}
const onDecrease = () => {
setNumber(prevNumber => prevNumber - 1);
}
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
08. input 상태 관리하기
- input 태그 : 리액트에서 사용자가 입력 할 수 있는 태그
1) src 디렉터리에 InputSample.js 파일 생성
import React from 'react';
const InputSample = () => {
return (
<div>
<input />
<button>초기화</button>
<div>
<b>값: </b>
</div>
</div>
);
}
export default InputSample;
2) App에서 렌더링
//App.js
import React from 'react';
import InputSample from './InputSample';
const App = () => {
return (
<InputSample />
);
}
export default App;
3) input의 onChange 라는 이벤트 사용
//inputSample.js
import React, { useState } from 'react';
const InputSample = () => {
const [text, setText] = useState('');
const onChange = (e) => { // e: 이벤트 객체
setText(e.target.value); // e.target : input DOM을 가리킴
}; //--> input에 입력한 값을 알 수 있음
const onReset = () => {
setText('');
};
return (
<div>
<input onChange={onChange} value={text} />
<button onClick={onReset}>초기화</button>
<div>
<b>값: {text}</b>
</div>
</div>
);
}
export default InputSample;
09. 여러개의 input 상태 관리하기
- placeholder : input이 비어져있을 때 input에 대한 설명을 보여주는 값
1) input 여러개 만들기, onChange와 onReset 함수 비우기
//InputSample.js
import React, { useState } from 'react';
function InputSample() {
const onChange = (e) => {
};
const onReset = () => {
};
return (
<div>
<input placeholder="이름" />
<input placeholder="닉네임" />
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
이름 (닉네임)
</div>
</div>
);
}
export default InputSample;
2) input에 name을 설정하고 이벤트가 발생했을 때 name 값을 참조하도록 함
(useState에서는 문자열이 아닌 객체 형태의 상태를 관리해주어야 함)
//InputSample.js
import React, { useState } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
※ 리액트 상태에서의 객체 수정법
- 새로운 객체를 만들어 변화를 주고, 이를 상태로 사용해야 함
setInputs({
...inputs,
[name]: value
});
'JS' 카테고리의 다른 글
리액트 훅(React Hook) (0) | 2024.08.02 |
---|---|
[2024 여름방학 React.js 스터디] #4주차 "리액트 입문(2)" (0) | 2024.08.02 |
[JS] async & await (1) | 2024.07.23 |
[JS] 프로미스(Promise) 이해하기 (2) | 2024.07.23 |
[JS] 비동기처리와 콜백함수 (0) | 2024.07.23 |