스터디에서 리액트 공식문서로 공부를 하고 있다.
어떤 분이 함수형리액트, 특히 useState를 이해하기 위해서는 클로저를 꼭 이해해야 한다는 말씀을 하셨다.
그말은 내가 useState,useEffect 등의 훅을 사용할 때 원리를 모른채, 사용 설명서만 외워두고 사용하고 있다는 것 을 상기시켜주었다.
저번주에 스터디를 마무리를 하면서 클로저가 어떻게 함수형리액트에 사용되는지 알아보자고 이야기를 했고 모든분들이 찬성해주셨다.
3일동안 한글자 한글자 천천히 읽었는데, 조금 이해가 가는 것 같다. 하지만 느낌만 알 뿐, 유창하게 설명할 정도는 아니다.
클로저
클로저 , 어렵다.
내가 내린 정의는 다음과 같다.(사실 구글링짬뽕)
함수가 생성되었을때 접근가능한 스코프를 기억하고, 전혀 다른 환경에서 실행될 때에도 여전히 그 스코프에 대한 참조를 유지할 수 있는 기능
=> 함수 실행이 종료되어도 생성된 시점에 접근 가능했던 모든 것에 계속 접근할 수 있게 된다.
다음 코드를 보자.
const handleNum = () => {
let num = 0;
const addNum = ()=>{num+=1;console.log(num)}
const minusNum = () => {num-=1;console.log(num)}
return [addNum,minusNum]
}
//이때 addNum과 minusNum이 생성되었을때의 환경, let num = 0; 을 기억한다.
const [plus,minus] = handleNum();
plus() //1
plus() //2
plus() //3
minus() //2
콘솔창에 console.log(num) 을 찍어보면 정의되지 않았다고 한다.
하지만 plus(),minus() 를 찍어보면 addNum(), minusNum() 이 생성되었을때 접근 가능했던 num에 대한 참조를 유지하고, 계속 num에 +1, -1 을 하고 있음을 알 수 있다.
이렇게 클로저를 통해 함수는 자신이 생성되었을때의 환경을 기억하고 참조를 유지한다는 것을 알 수 있다.
또한 위에서 console.log(num)을 찍었을 때 ReferenceError가 나타나는 것으로 클로저는 변수를 은닉함을 알 수 있다.
“Closure makes it possible for a function to have ‘private’ variables.”
즉, 클로저를 통해 함수의 private한 변수를 생성하고 관리하고 해당 함수를 호출할 때 마다 이 private한 변수에 접근할 수 있다.
useState에서 클로저
리액트는 이전 state와 현재 state를 비교하여, 리렌더링 여부를 결정한다.
이때 이전 state를 기억하기 위해 클로저를 사용한다.
클로저 : 함수가 생성되었을때 접근 가능했던 변수에 대한 참조를 기억하고 유지
위에서 handleNum() 코드를 이해했다면 이 코드가 변수이름만 다른 코드라고 느껴질 것이다.
아마 설명을 읽을 필요가 없을 듯. (출처)
//import {useState} from 'react'
const React = (function() {
let _val;
function useState(initVal) {
const state = _val || initVal;
const setState = newVal => {
_val = newVal;
};
return [state, setState];
}
function render(Component) {
const C = Component();
C.render();
return C;
}
return { useState, render };
})();
function Component() {
//[count,setCount]가 정의될 때,
//[state,setState]가 생성될때의 환경, let _val = 0 을 기억한다.
const [count, setCount] = React.useState(1);
return {
render: () => console.log(count),
click: () => setCount(count + 1),
}
}
var App = React.render(Component);
App.click(); // 1
var App = React.render(Component);
App.click(); // 2
var App = React.render(Component);
App.click(); // 3
React함수 내부에서 state,setState가 생성될 때, 이 함수들이 접근 가능했던 환경, let _val = 0에 대한 참조를 기억할 수 있다.
또한 _val을 private하게 관리할 수 있기에, 각 컴포넌트만의 상태값을 각각 관리할 수 있다.
const React = (function() {
let _val;
function useState(initVal) {
const state = _val || initVal;
const setState = newVal => {
_val = newVal;
};
return [state, setState];
}
...(생략)...
})();
function Component() {
//[count,setCount]가 정의될 때,
//[state,setState]가 생성될때의 환경, let _val = 0 을 기억한다.
const [count, setCount] = React.useState(1);
참고문서
'개발 > React' 카테고리의 다른 글
react 18로 업글시 children 타입에러 : Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes'. (0) | 2023.01.30 |
---|---|
useEffect cleanup은 state초기화 이후에 실행된다. (0) | 2022.12.10 |
TIL : onBlur때문에 onClick이 실행되지 않을 땐, onMouseDown을 사용 (0) | 2022.11.04 |
React 튜토리얼에 있는 class형 컴포넌트.. (0) | 2022.11.01 |
state를 직접 변경하지 않고 useState로 변경해야 하는 이유 (0) | 2022.10.07 |