[React] 몰아듣기...
리액트를 쓰는 이유 : https://github.com/academind/react-complete-guide-code/tree/01-getting-started/code/react-vs-vanilla-js-example
리액트의 대안 : https://academind.com/tutorials/angular-vs-react-vs-vue-my-thoughts
-----------------
nodejs 설치 : https://nodejs.org/ko/
강의에서는 최신 버전을 설치하라고 했지만 나는 LTS파이다... ㅋㅋㅋ
이제 리액트 프로잭트 만들 수 있다!!
https://github.com/facebook/create-react-app
GitHub - facebook/create-react-app: Set up a modern web app by running one command.
Set up a modern web app by running one command. Contribute to facebook/create-react-app development by creating an account on GitHub.
github.com
npx create-react-app my-app
cd my-app
npm start
vscode를 추천함!
prettier - code formatter 추천함 Keyboard Shortcuts에서 ‘format document’를 검색하면 단축키 사용 가능
리액트 이제 시작!!!
index.js 파일!!
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
//처음에 브라우저에서 이 프로잭트를 접근했을 때 진입점 파일!!!
ReactDOM.render(<App />, document.getElementById('root')); //이 코드의 실행결과를 브라우저에 보여줌!!
<App /> 은 js 속의 html 코드이고 사실 jsx 문법임!! 그리고 두번째 인수는 <App />가 어디에 렌더링 되어야 하는지 보여준다. 여기에서index.html 파일에서 root라는 아이디를 가진 요소를 찾아서 src 폴더 안에 있는 app.js 파일을 넣으라는(?) 이야기이다!!
//src/app.js
function App() {
return <div>Hello!</div>; //컴포넌트는 무조건 브라우저에 렌러일 될 수 있는 값을 반환해야하는데, 보통 html 코드이다.
}
export default App;
컴포넌트에서 return하는 값은 html처럼 보이지만 사실은 js이기 때문에 class가 아니고 className으로 작성해야한다!!
function App(){
return(
<div>
<h1>My Todos</h1>
<div className='card'>
<h2>TITLE</h2>
<div className="actions">
<button className="btn">Delete</button>
</div>
</div>
</div>
);
}
export default App;
하지만 className은 좀 특이한 경우라고 한다!
다른 컴포넌트 빌드 및 재사용하는 방법
함수의 이름은 대문자로 시작해야한다!! 내장 html element와 구별해주기 위해서이다!! (뷰랑비슷한데?!) 개발자가 만든 요소라면 무조건 대문자1!! 대문자!!!
// src/component/Todo.js
function Todo() {
return (
<div className='card'>
<h2>TITLE</h2>
<div className="actions">
<button className="btn">Delete</button>
</div>
</div>
);
}
export default Todo;
위에서 만든 컴포넌트를 이렇게 html 요소 처럼 사용하면 된다.
import Todo from './component/Todo'
function App(){
return(
<div>
<h1>My Todos</h1>
<Todo />
<Todo />
<Todo />
<Todo />
</div>
);
}
export default App;
하지만 이렇게 사용하면 문제가 있는데!!!! 바로.... Todo 컴포넌트가 항상 같은 값만 출력한다는 것이다!!
그래서 Todo 컴포넌트를 사용하는 app.js에서 데이터를 넘겨주자1!!
"props" 및 동적 콘텐츠 작업하기
//App.js
import Todo from './component/Todo'
function App(){
return(
<div>
<h1>My Todos</h1>
<Todo text='리액트 배우기' />
<Todo text='뷰 배우기' />
<Todo text='바닐라 배우기' />
</div>
);
}
export default App;
Todo에 text라는 속성을 만들어주고!! 각자 원하는 값을 넣어준다.
이후에 Todo 컴포넌트에서는 props라는 매개변수를 넣어주고 props.text로 접근해서 사용해준다!! 부모한테 속성 값을 받아서 쓰는거다!!
// Todo.js
function Todo(props) {
return (
<div className='card'>
<h2>{props.text}</h2>
<div className="actions">
<button className="btn">Delete</button>
</div>
</div>
);
}
export default Todo;
{ } 중괄호(동적표현식)를 넣어주면 js코드로 동작한다!! 여기에는 {2 + 2}와 같이 한 줄의 표현식을 작성할 수 있다. 하지만 if문과 같은 block문은 작성할 수 없다.
이벤트 처리하기!!
onClick에 동적표현식을 쓰는데, 그 안에는 함수를 호출(실행)하면 안된다!! 그냥 함수값을 넣어야한다. (걍 호출하는 소괄호'()'를 빼고 함수 이름만 넣으라는 뜻) 함수를 실행하면 js와 리액트가 코드를 검증할 때 실행이 되어 버리기 떄문이다!!
function Todo(props) {
function deleteHandler() {
console.log('clicked!!');
console.log(props.text);
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className="actions">
<button className="btn" onClick={deleteHandler} >Delete</button>
</div>
</div>
);
}
export default Todo;
더 많은 컴포넌트 추가하기!!
컴포넌트에서 길고 너무 복잡한 로직을 관리하면 안된다! 다 작은 단위로 쪼개주는 것이 좋다.
modal이랑 backdrop 컴포넌트를 만들고 사용해보겠다!!
//modal.js
function Modal() {
return
<div className="modal">
<p>Are you Sure??</p>
<button className="btn btn--alt"> Cancel</button>
<button className="btn">Confirm</button>
</div>
}
export default Modal;
//Backdrop js
function Backdrop() {
return <div className="backdrop" />
}
export default Backdrop;
이렇게 두 개의 컴포넌트를 만들어 준 다음에 App.js에서 불러온 다음 사용할 수 있다.
//App.js
import Todo from './component/Todo'
import Modal from './component/Modal';
import Backdrop from './component/Backdrop';
function App(){
return(
<div>
<h1>My Todos</h1>
<Todo text='리액트 배우기' />
<Todo text='뷰 배우기' />
<Todo text='바닐라 배우기' />
<Modal />
<Backdrop />
</div>
);
}
export default App;
하지만 이렇게 하면 모달창에 아무런 반응이 없다. 즉 완전히 정적인 사이트이다!! 이를 해결하기 위해서 state를 알아보자!!!
State란..?
지금 상태에서 다른 상태로 바뀔 수 있어야 한다1! 예를들면 버튼을 누르면 modal과 backdrop이 열리고 버튼이나 backdrop을 누르면 모달이 닫혀야 한다!! https://github.com/dadafly1244/TIL/tree/e99005de84d929fe23786c19d2dffaea4107a8b6
useState의 초기 값을 매개 변수로 전달할 수있음. 배열을 리턴함. 첫번째 값은 현재 state의 snapshot,
import Todo from './component/Todo'
function App(){
return(
<div>
<h1>My Todos</h1>
<Todo text='리액트 배우기' />
<Todo text='뷰 배우기' />
<Todo text='바닐라 배우기' />
</div>
);
}
export default App;
import { useState } from 'react'
import Modal from './Modal';
import Backdrop from './Backdrop';
function Todo(props) {
const [modalIsOpen, setModalIsOpen ]= useState(false);
function deleteHandler() {
console.log('clicked!!');
console.log(props.text);
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className="actions">
<button className="btn" onClick={deleteHandler} >Delete</button>
</div>
{modalIsOpen && <Modal />}
{modalIsOpen && <Backdrop />}
</div>
);
}
export default Todo;
event props로 작업하기. 기능을 props로 전달하기
함수는 일급객체이기 때문에 값으로 전달할 수 있다. 그리고 backdrop과 같이 우리가 만든 컴포넌트는 직접 onClick과 같은 이벤트를 props로 전달해주어야 한다!!
import { useState } from 'react'
import Modal from './Modal';
import Backdrop from './Backdrop';
function Todo(props) {
const [modalIsOpen, setModalIsOpen ]= useState(false);
function deleteHandler() {
// console.log('clicked!!');
// console.log(props.text);
setModalIsOpen(true);
}
function closeModalHandler () {
setModalIsOpen(false)
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className="actions">
<button className="btn" onClick={deleteHandler} >Delete</button>
</div>
{modalIsOpen && <Modal />}
{modalIsOpen && <Backdrop onClick={closeModalHandler} />}
</div>
);
}
export default Todo;
function Backdrop(props) {
return <div className="backdrop" onClick={props.onClick} />
}
export default Backdrop;
그럼 사용할때도 'props.설정한이름'으로 불러오면 된다!!