웹개발 공부는 10월 초부터 시작했는데 정리를 지금부터 하게 됐습니다^.^;
리액트는 자바스크립트를 통해 html를 생성한다. 바닐라 자바스크립트는 html을 통해 자바스크립트 소스코드를 생성하므로 방향성이 다르다.
리액트는 라이브러리인데 이미 누군가 구현한 것을 배워서 갖다 쓰면 된다. 상호작용이 많아질 때 쓰기 좋은 라이브러리라고 한다. 바닐라 자바스크립트를 베이스로 하므로 리액트를 배웠다고 해서 자바스크립트 공부를 게을리하면 안됨!
실습을 위해서 html파일 위에 소스를 바로 작성할건데, 이때
을 불러와야 한다. 아래의 소스를 추가하면 된다.
리액트 라이브러리
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
리엑트 돔
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
소스코드 내에서 html태그를 생성하기 위해서 React.createElement(태그이름, 태그속성, 콘텐츠)
함수를 사용한다. 첫번째 매개변수는 생성할 태그, 두번째 매개변수는 속성값, 세번째 매개변수는 콘텐츠값이다.
속성값에 onClick 등 이벤트리스너를 만들어야 추가할 수 있는 속성도 직접 커스텀할 수 있다.
const btn = React.createElement(
"button",
{onClick: ()=>console.log("clicked"),},
"click me"
);
소스코드로 만들어진 html태그를 실제 웹에 붙여넣기 위해서 ReactDOM.render(생성한 태그, 붙여넣을 태그)
함수를 사용한다.
ReactDOM.render(btn, root);
위에서 정리한 createElement는 실습에서 거의 사용하지 않는 방식이라고 한다. 더 쉬운 방법이 있기 때문이다. 바로 JSX!
JSX를 이용하면 자바스크립트 내에서 요소를 생성할 때 html형식을 빌릴 수 있다.
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
JSX는 내장되어 있지 않으므로 JSX를 읽기 위해 html파일에 해당 소스를 붙여넣고 시작한다.
코드를 작성할 script의 태그 옵션에 type="text/babel"
을 추가해야 해당 코드의 JSX를 읽어낼 수 있으므로 추가해준다.
React.createElement()와 기능적으로 유사하지만 더 직관적은 방법은 다음과 같다.
const btn = (
<button onclick={() => console.log("clicked")}>
click me
</button>
);
이런 식으로 실제 html태그의 형식을 빌리면서 onClick등 이벤트리스너 기능도 옵션인 척 끼워넣을 수 있다.
그런데 신경써야할게 하나 있다. JSX 안에 JSX로 만든 태그를 추가하고 싶다면 어떻게 해야할까? (js에서 append함수의 기능)
그 때 주의해야 할 부분은 두개다.
이 두가지 조건을 만족하면 새로 만들 JSX 안에 JSX로 만든 태그를 넣을 수 있다.
const Btn = () => (
<button
onclick={() => console.log("clicked")}
>
click me
</button>
);
이런식으로 조건을 만족했다면 새로 만들 태그에 그대로 붙여주면 된다.
const Container = (
<div>
<Btn /> //대문자 컴포넌트
</div>
);
공부하면서 굳이 함수로 만들어서 넘기는 이유에 대해 궁금했는데 이후에 컴포넌트가 다른 역할도 수행할 수 있고, 그런 기능으로 상호작용하려고 만들어진게 리액트이기 때문에 함수 형태로 넘겨주는거라고 한다.
부가적인 기능 없이 단순히 태그를 붙이고싶은 거라면 굳이 함수로 만들지 않고 변수를 {
}
로 감싼 뒤에 JSX 태그 안에 넣어줘도 된다.
state는 기본적으로 데이터가 저장되는 곳이다.
데이터를 저장하고 자동으로 렌더링 시킬 수 있는 방법은 React.useState()
함수를 사용하는 것이다.
const data=React.useState(0);
이렇게 선언하면 date 변수 안에는 [0,f] 형태의 배열이 저장된다. 첫번째 인덱스의 0은 데이터 초기값, 두번째 인덱스의 f는 데이터에 적용할 함수이다.
만들어진 배열을 사용하기 쉽게 하기 위해서 자바스크립트의 배열 문법을 보고 넘어갈 것이다.
const A = ["potato","tomato"];
const [MyFavFood, MySecondFood] = A;
MyFavFood: potato
MySecondFood: tomato
즉 배열A을 배열B에 저장하면 배열B 안의 변수 값을 배열A의 데이터로 설정할 수 있다.
위와 같은 문법은 구조 분해 할당을 통해 변수로 선언한 것이기 때문에 MyFavFood, MySecondFood는 여러 번 사용할 수 있게 된다.
배열의 각 인덱스를 일종의 변수로 사용하는 방법인데, 따라서 각각의 데이터에 '
나 "
등을 붙여 문자열로 만들지 않는 것에 주의해야 한다.
(const 'x' = 1; 이런 식의 선언은 하지 못함!)
다시 useState함수로 돌아와서, 구조분해할당으로 useState()의 인자들을 받아올 것이다.
const [counter, modifier] = React.useState(0);
이렇게 만들어진 modifier는 counter의 값을 변경할 뿐만 아니라 counter가 나오는 화면을 리렌더링 한다.
따라서 바닐라 자바스크립트에서 innerText를 열심히 고치던 과정을 생략할 수 있다.
이렇게 화면이 리렌더링될 때 모든 컴포넌트가 리렌더링 되는 것이 아니라 업데이트 된 일부분만이 리렌더링되므로 바닐라 자바스크립트보다 효율적인 렌더링이 가능하다.
위의 설명을 토대로 바닐라 자바스크립트로 작성한 예제를 리액트로 수정했다.
<!--바닐라 자바스크립트-->
<!DOCTYPE html>
<html>
<body>
<sapn id="cnt">Total clicks: 0</sapn>
<button id="btn">click me</button>
</body>
<script>
let cnt=0;
const button=document.querySelector("#btn");
const span=document.querySelector("#cnt");
function handleClick(){
console.log("i have been clicked");
cnt++;
span.innerText=`Total clicks: `+cnt;
}
button.addEventListener("click",handleClick);
</script>
</html>
<!--리액트-->
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.querySelector("#root");
function Container() {
const [counter, setCounter] = React.useState(0);
const onClick = () => {
setCounter(counter + 1);
};
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<Container />, root);
</script>
</html>
리액트가 더 복잡한거 같은데?🤔
당장은 이런 생각이 들지만 코드를 대충 훑어봤을 때 리액트 쪽이 더 직관적인 느낌이다.
사용하는 태그가 많고 복잡한 프로젝트에서 일일히 변수 선언하고 이벤트리스너 다는 것보다 리액트로 작업하는게 편하고 리렌더링 효율도 좋을 것 같다.