그 이유는 handleClick함수 안의 setState가 비동기식 함수여서 아직 +1한 값이 this.state.number에 반영되지 않았는데
바로 다음 줄인 console.log가 실행돼서 더한 값이 반영되지 않은 this.state.number를 찍었기 때문이다.
handleClick함수를 호출했을 때 다음과 같은 과정으로 진행된다.
handleClick호출 -> setState는 Task queue에 호출됨 -> console.log실행&결과 -> setState실행&결과
->render업데이트 반영
만약에 handleLogClick이라는 함수가 있다고 가정해보자.
handleLogClick = () => {
console.log(this.state.number)
}
handleClick을 호출 후 handleLogClick을 호출하면 다음과 같은 순서로 진행된다.
handleClick호출 -> setState는 Task queue에 호출됨-> console.log실행&결과 -> setState실행&결과
->render업데이트 반영 -> handleLogClick호출
즉, handleClick이라는 이벤트가 완전히 끝날 때까지 handLogClick은 시작되지 않는다!
그래서 handLogClick은 최신값을 가지게 되는 것이다.
반면에 Current Number옆의 {this.state.number}는 handleClick함수가 끝난 후에 render에서 쓰인 것이기 때문에 최신상태로
반영된 것이다.
그렇다면 handleClick함수 안에서 어떻게 바로 최신으로 반영된 this.state.number를 볼 수 있을까?
배칭은 React가 더 나은 성능을 위해 여러 개의 state 업데이트를 하나의 리렌더링 (re-render)로 묶는 것을 의미한다.
예를들어, 하나의 클릭 이벤트 안에 두 개의 state 업데이트를 가지고 있다면, React는 언제나 이 작업을 배칭하여 하나의 리렌더링으로 만들었다. 다음과 같은 코드를 실행해보면, 매 번 누를 때마다, state를 두 번 변경하였지만, React가 단 한 번의 렌더링만 수행한 것을 볼 수 있다.
function App() {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
function handleClick() {
setCount((c) => c + 1); // 아직 리렌더링 하지 않는다
setFlag((f) => !f); // 아직 리렌더링 하지 않는다
// React는 이 함수가 끝나면 리렌더링을 한다 (이것이 배칭이다!)
}
return (
<div>
<button onClick={handleClick}>Next</button>
<h1 style=>{count}</h1>
</div>
);
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.gitignore는 git에서 무시할 애들을 적어놓는 것이다.
node.modules가 적혀있다. 여기에 적혀있는 애들은 다 깃으로 관리를 안한다.
우리가 git add ,commit ,push를 해도 깃허브에 안올라간다.
node_modules에 우리가 필요한 패키지가 다 들어가는데 왜 git에 안올리는 걸까?
용량이 너무 크기떄문에 무거워서 그렇다.
근데 얘네가 없으면 안돌아가기 때문에 필요하긴 필요하다. 그래서 우리가 package.json의 dependencies에 집어넣었다.
node_modules를 안올려도 되는 이유는 dependencies에 다 명시가 되어 있으면 명령어 하나면 여기에 있는 애들이 다
다운로드 받아져 node_modules를 채워진다.
npm install을 치면 패키지 안의 dependencies에 있는 정보를 다 읽는다. 그걸 다 읽고 거기에 있을걸 npm에서 다 다운로드 받아준다.
그래서 dependencies는 잘 관리해야한다. 내가 잘못해서 정보를 지우면 다른 사람이 내 패키지를 쓸 때 실행이 안되는 일이 일어난다.
우리가 개발하면서 새로운 패키지들을 쓸 수도 있는데
그때도 꼭 dependencies에 꼭 넣어줘야한다. npm으로 install 하면 뒤에 --save하고 적어 놓으면 dependencies에 자동으로 추가가 된다.
import React from "react";
import ReactDOM form "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(<App />, document.getElementById('root'));
3,4번째는 상대경로가 붙어 있는데 1,2번째는 그냥 string에 바로 적혀있다.
이런 애들은 node_modules에서 바로 끌고 오는 것이다.
node_modules에서 끌고올 때는 바로 스트링으로 적는다.
node_modules안의 react라는 폴더에서 가져오는 것이다. react-dom라는 폴더에서 가져오는 것이다.
밑에서 ReactDom을 쓰고있는데 이건 뭘까? ReactDom하고 .하고 render가 들어갔다 이렇게 생긴애를 객체(object)라고 한다.
객체에 있는 어떤 것들을 접근하기 위해서 .을 써서 들어간다.
ReactDom 다른사람들이 만들어 놓은 객체이다.
ReactDom객체 안의 render라는 프로퍼티(속성)안에 들어갔다. 그리고 괄호가 열리고 닫혔다. 괄호가 열리고 닫히는건 함수를 호출하는 표시다.
리액트돔안에 랜더라는 함수(메소드)가 있고 이걸 호출해서 인자를 두개 넣어주고 있는 것이다.
첫번째 인자로 뭘 랜더 시킬 것인지.
두번째 인자로 어디 안에 랜더 시킬 것인지.
해당 페이지가 어떻게 구성되어 있는지 파악 용이
- 예시
컴포넌트는 하나의 레고 블럭이라고 이해하면 된다.
차가 두개 있는데 위에는 레고블럭 컴포넌트 단위로 개발한 자동차이다.
아래는 하나의 통으로 찍혀져 있다. 중간에 레고처럼 나뉘어져 있지 않다.
코드의 재활용이 증가된다는 말은 바퀴는 똑같이 생겼는데 네 개 들어가는 것이다.
왼쪽 오른쪽만 살짝 바꿔 주면 된다.
그런데 그걸 판으로 찍으면 네개다 만들어야 한다.
컴포넌트를 쓰면 이런 바퀴의 틀 하나 잡아놓고 네 개를 만들어서 쓰면 끝나는 문제다.
그러니 코드의 재활용이 증가되고 유지보수가 용이하다는 말은 여기 밑에 있는 자동차에서
문의 색을 바꾸고 창문을 늘리고 싶다.
그러면 통으로 찍혀있으니까 문만 바꿀 수는 없으니 처음부터 새로 만들어야 한다.
위에 같은 경우에는 블록단위로 만들어져 있다. 문도 블록단위이니 색을 바꾸고 싶으면 문의 블록만
바꿔끼우면 된다.
이런면에서 코드의 유지보수가 용이하다는 것이다.
그리고 해당페이지가 어떻게 구성되어있는지 파악이 용이하다는 것은
아래는 뚜껑이 어디까지인지 말하기 애매하다.
위에는 한 부품이 뚜껑이다. 본넷이다. 문이다 말할 수 있다. 해당페이지가 뭘로 구성되어있는지 파악하기 쉽다.
컴포넌트의 또 다른 특징은 컴포넌트는 또 다른 컴포넌트를 포함 할 수 있다.
부모자식 컴포넌트로 표현한다.
문안의 손잡이도 컴포넌트로 만들 수 있는데 문이라는 컴포넌트에 속하게 만들 수 있다.
작은 컴포넌트 -> 중간 컴포넌트 -> 큰 컴포넌트 이런식으로 개발하는게 컴포넌트 단위개발이라고 한다.
에전에는 함수로는 상태관리가 안돼서 class형태로 주로 사용했지만 지금은 함수에 hook이라는 새로운 기술이 나오면서
요즘에는 다 함수형으로 사용한다.
ui와 자바스크립트 로직은 뗄레야 뗄 수 없는 사이인데 이것을 계속 따로 쓰다보니까 너무 불편해서
그러면 그냥 자바스크립 파일 안에서 이런 마크업까지 다 같이 해버리자 라는 컨셉으로 나온게 jsx이다.
얘는 말그대로 확장문법이기 때문에 실제로 웹 브라우저가 읽어서 해석하지를 못한다.
그래서 그 중간에 많은 패키지 중에서 babel이란 번역을 해주는 패키지가 있는데 이게 계속 jsx를 읽고html을 만드는 과정을 해준다.
그래서 얘가 컴파일에서 나간다라고 보면 된다.
jsx의 특징 4가지
1.형제구조로 이루어질 수 없다. 최상위로 하나가 감싸져서 하나의 단일 태그가 되어야 한다.
import React from "react";
class Login extends React.Component { //에러!
render(){
return(
<div>Hello</div>
<div>world</div>
)
}
}
class Login extends React.Component { //성공!
render(){
return(
<div>
<div>Hello</div>
<div>world</div>
</div>
)
}
}
class Login extends React.Component { //성공!
render(){
return(
<>
<div>Hello</div>
<div>world</div>
</>
)
}
}
export default Login;
//부모가 하나로 감싸기는 해야하는데 실질적으로 얘한테 스타일링을 줄 것도 아니고 실제로 쓰는 애가 아니다라고 하면은
//프레그먼트(fragment) <> </> 라는걸 쓸 수 있다.
fragment를 썼을 때 랜더 결과
2.class = "" 가 아니라 className=""으로 써야한다.
3.jsx는 자바스크립트 안에서 쓰는 html이다. 그러므로 이 안에 자바스크립트를 넣어줄 수도 있다. jsx안에서 자바스크립트를 쓸 땐 중괄호를 써줘야한다.
4.addeventlistener같은걸 안써도 바로 태그안에서 이벤트를 붙일 수 있다.
import React from "react";
class Login extends React.Component {
render(){
return(
<>
<div className="title" onClick = {() => alert("Function trigger")}
style={{color: "red"}}>
{"Hell" + "O"}
</div>
</>
)
}
}
export default Login;
//{"Hell" + O} => 자바스크립트 연산이 돼서 HellO라고 나옴
//onClik이 됐을 때 {}안의 자바스크립트 함수를 실행시켜라
//인라인 스타일도 줄 수 있다. 인라인 스타일은 객체형태로 들어가야한다. 객체는? 자바스크립트다. 그래서
//중괄호 한 번 열고 그안에 객체가 들어가니까 중괄호를 한 번 더 넣어야한다. 즉, 두번 중첩된 형태로 나온다.