그렇다보니 데이터를 가지고 놀때 useState를 통해 값을 처리하고 setState를 통해 변경하고 변경된 UI부분만 재 처리하는 작업을 반복하는데, 해당값을 상위의 컴포넌트부터 최하단의 컴포넌트까지 복잡한 구조를 props를 통해 넘겨야한다면 굉장히 불필요한 데이터 전달처리로 소스도 난잡해지고 중간 중간의 컴포넌트들은 사용하지도 않는 props데이터를 넘기다보니 처음 소스를 받는사람은 이건 뭔데 넘기고 있을까? 라는 생각을 가질 수도 있을 것이다.
이럴때 전역 state처리를 해주는 redux나 recoil이 있는데, recoil에 대하여 알아보고자 한다.
Recoil
recoil은 state management 라이브러리로 페이스북팀에서 만들었고, 굉장히 간결하고 강력하다.
실제 예시를 보고 개념도 쉽고 그림도 잘 그려져서 너무 좋았다.
설치하기
먼저 사용을 해보기 위해 설치를 해야한다.
npm install recoil
설치가 끝나면 recoil설정 파일이 필요하다.
recoil에서 특정 전역처리를 하는 영역 덩어리를 atom이라고 부른다.
atoms.ts파일을 열어주고
전역 state를 처리할 값을 입력해주고 필요한 부분들에서 불러서 사용하면 된다.
그 전에 전체를 RecoilRoot로 App을 감싸주는걸 잊지 말자!
-atom
atoms.ts
import { atom } from "recoil";
export const isDarkAtom = atom({
key: "isDark",
default: true,
})
atom에는 key와 default값을 object형태로 넣어준다.
key값은 global state로 사용할 key값이고, default는 기본 값이다. 기본값으로 인해 자료형도 선택이 된다.
- useRecoilValue
전역 state값 불러오기
파라미터에는 호출할 atom을 넣어줍니다.
import { isDarkAtom } from "../atoms";
import { useRecoilValue } from "recoil";
const isDark = useRecoilValue(isDarkAtom);
- useSetRecoilState
전역 state값 변경하기
파라미터에는 호출할 atom을 넣어줍니다.
import { isDarkAtom } from "../atoms";
import { useSetRecoilState } from "recoil";
const setIsDark = useSetRecoilState(isDarkAtom);
setIsDark(true); //atom의 state값 변경
- 값불러오고 변경하기를 useState처럼 처리하기
파라미터에는 호출할 atom을 넣어줍니다.
import { useRecoilState } from "recoil";
import { isDarkAtom } from "../atoms";
const [isDark, setIsDark] = useRecoilState(isDarkAtom);
console.log(isDark);
setIsDark(true);
많이 보던 형태가 아닐까 싶습니다.
바로 useState랑 생김새가 똑같습니다.
값만 불러야하거나 변경만 해야하면 위에서처럼 하나만 import해서 쓰면 되지만, 둘다 필요한 경우에는 해당 방식이 좋아보입니다. :)
react-hook-form을 사용하여 form태그 내의 input태그의 onChange이벤트, 유효성 검사, submit후 데이터 값 확인 등 다양한 작업을 손쉽게 처리 할 수 있습니다.
기존의 react를 사용하여 해당 기능을 처리하려면 useState를 통해 처리할 값고 set함수를 선언하고 onChange이벤트에 넣어주고 value값에 state값을 넣어주고, 유효성을 체크하려면 onChange에 걸어둔 함수에서 길이를 체크하거나 정규식으로 패턴을 검사하거나 한개의 input만 해도 아주 복잡한 코드가 만들어지는데, 복잡한 회원가입이나 입력폼에서 이 과정을 실행하려면 상당한 긴 소스가 작성될 것입니다. 이런 문제를 간단하게 해결해 줄 수 있습니다.
먼저 설치를 진행합니다.
npm install react-hook-form
기본적으로 사용을 위해서 useForm이라는 hook을 항상 import해서 사용합니다.
import { useForm } from "react-hook-form"
1. register
register는 input 기능에 특화되어 있는 함수로 onBlur, onChange를 가지고 있는 함수입니다.
처리하고자 하는 input태그 내에 {...register("name")} 하나만으로 모든 처리가 끝납니다.
id는 A-Z, a-z로 시작해야하며, 이후 문자, 숫자, '-', '_', '.'이 올 수 있습니다.
HTML5
HTML5로 올라오면서 공백을 제외하고 대부분의 값을 받아들입니다.
숫자로만 구성되거나, 밑줄로 시작하거나 점만으로 구성되어도 가능합니다.
4, 5는 이러한 차이점이 발생하고 있는데, 5로 올라오면서 허용된 대부분의 값이 문제가 되고 있습니다.
특히나 css에서 .과 :는 선택자로서 특별한 의미를 지니는데, id값에 .과 :가 있게되면 css측에서는 혼돈이 발생됩니다.
"."이 있는 id값에 css적용하기
<style>
#abc.def{color: yellowgreen} //abc라는 id를 가지면서 def라는 클래스를 가진 요소에 적용
#abc\.def{color: yellowgreen} //\역슬래쉬를 통해 처리
</style>
<h1 id="abc.def">TEST</h1>
안그래도 복잡한 구조에 역슬래쉬까지 추가해서 제어를 해야합니다.
저라면 정말 어쩔수 없는 특별한 상황이 아니라면 사용하고 싶지 않군요.
다른 스택오버플로우나 블로그 글들에서도 볼 수 있듯 숫자로 시작하는 id값 생성과 제어는 js까진 사용 가능하지만
html4처럼 기존의 양식을 지키는 형태로 작성하며, 문자[A-Za-z]로 시작하고, ':', '.'와 같은 특수문자보단 '-', '_'를 사용하거나 카멜표기법을 따르는것을 권장합니다.
웹 개발자로 년차가 쌓이고 있는 현 시점에서 자바스크립트의 내부 동작을 이해할 필요가 있었다. 자바스크립트의 내부에서 어떤식으로 돌아가는지에 대한 내용들을 파악해보고 참고한 내용들을 참고하여 작성하는 글이다.
🪄자바스크립트의 변화
과거 웹 페이지의 동작만을 위해 동작하던 자바스크립트는 현대에 와서 많은 변화가 있었는데, 더 이상 웹 페이지만을 위해 존재하지 않는다. 2008년 구글에서 V8엔진을 사용하여 크롬을 출시한다. 이를 시작으로 2009년 노드가 탄생하였고, 서버와 클라이언트, 어플리케이션 개발 등 다양한 분야에서 사용되게 된다.
🔥자바스크립트 엔진
V8은 자바스크립트의 엔진이다. 크롬 브라우저의 엔진이면서, Node.js의 기반이다. 싱글스레드로 동작하면서 메모리힙과 콜스택으로 구성되어 있다.
메모리 힙(Memory Heap): 원시타입(Primitive type), 객체(Array, Object, Function 등)타입이 선언되면 메모리힙에 할당된다. 사용이 끝나면 자동으로 해제(Garbage collection)된다. 콜스택(Call Stack): 실행해야 할 코드가 쌓인다.
🧙Call Stack
실행할 코드가 쌓인다고 가볍게 설명했는데, 더 자세히 알아보자. 일단 여기서 이름 자체에 Stack이라는 키워드로 어느정도 동작을 유추할 수 있다. 후입선출를 가진 스택은 마지막에 쌓인 데이터가 먼저 출력되는 방식이다. 요청이 들어올 때마다 이 콜스택이라는곳에 쌓아두는데, 아래와 같은 소스가 있다면 어떻게 쌓이고 동작할까?
function tenSum(x){
return x + 10;
}
function printSum(x){
const sum = tenSum(x);
console.log(sum);
}
printSum(5);
console.log("start", new Date())
setTimeout(()=>{console.log("setTimeout", new Date())}, 0);
const wakeUpTime = Date.now() + 1000;
while (Date.now() < wakeUpTime) {}
console.log("test1");
console.log("test2");
console.log("test3");
console.log("end", new Date())
위 소스에 대해 설명하자면 아래와 같다
단순 console.log를 실행한다.
setTimeout이 동작한다. 동작시간은 0초로 설정하였다.
이후 현재시간의 1초뒤의 시간을 wakeUpTime에 작성하여 while문에서 시간으로 체크한다.
1초동안 강제로 동기화를 시켜서 페이지가 살짝 멈추게 된다.
이후 단순한 console.log들을 출력한다.
예상한 결과가 나오길 빌면서 아래 출력 결과를 공유한다.
setTimeout메소드가 2번째에 있고 동작시간을 0으로 처리했음에도 콜백안에 있는 console.log는 가장 나중에 출력되고 있는걸 볼 수 있다. 심지어 4번째 while문에서 강제로 블로킹 처리를 해서 페이지가 멈추는 현상까지 발생는데 어떻게 이런 결과가 나왔을까? 이런 현상에 대해서는 이벤트 루프, 테스트 큐에 대해 알아야한다.
먼저 테스크 큐는 콜백 함수들이 대기하는 큐 형태이다. Queue는 선입선출 구조로 먼저 들어온 것들이 먼저 나간다. 위 예제의 실제 동작을 설명하자면 아래와 같다.
콜스택에 console,log("start")가 push되고 출력되면서 pop된다.
setTimeout이 콜스택에 push되고 콜백 내용이 테스크 큐에 등록되면서 pop된다.
0ms가 지나고 이벤트 큐는 콜 스택이 비워질때까지 기다리면서 콜백을 실행시킬 준비를 한다.
wakeUpTime의 변수가 메모리 힙에 올라가고 이후부턴 콜스택들이 동작된다...
위와 같은 비동기 처리나 I/O의 작업이 자바스크립트에서 발생하면 콜백함수가 콜스택에서 처리되는게 아니라 별도의 테스크 큐라는 곳에 쌓였다가 이벤트 루프에 의해 실행되기 때문에 뜻밖의 결과를 얻을 수 있다.
⭐브라우저의 내부 환경
자바스크립트의 엔진을 구동하는 환경의 브라우저의 내부 모습은 아래와 같다.
그림에서도 볼 수 있듯이 개발하면서 자주 사용했던 Ajax, setTimeout과 같은 비동기 처리들은 자바스크립트가 해주는게 아니라 Web API영역에 따로 정의되어 있다. Node.JS에서는 동시성을 위해 libuv라이브러리를 도입했는데, 이 libuv라이브러리가 이벤트 루프를 제공한다.
정리하자면 비동기 작업을 하게되면 Node.js의 API가 호출되고, 그러면서 작성된 콜백 함수들은 이벤트 루프에 의해 관리가 되고 실행이 된다.