day 05

유요한·2022년 11월 23일
0
post-thumbnail

hook함수

react는 어떠한 상태를 갖고 있고 그 상태가 변경됨에 따라 가상 돔의 dom을 dom API 적용

이러한 react의 상태의 생명 주기를 관리하는 함수 또한 훅 함수를 통해 상태를 통한 이벤트를 실행할 수 있음

ex)

  • state가 변동되었을 시 함수 실행
  • 컴포넌트가 처음 열렸을 때(나타났을 때) 실행
  • 컴포넌트가 눈에 안보였을 때 실행하는 이벤트
  1. useState

  2. useRef

  3. useMemo

  4. useCallback

  5. useEffect

  6. custom Hook


State 불변성(object)

const obj = {}
const obj2 = {}

obj === obj2 // false

obj3 = obj
obj === obj3 // true

얕은 복사 → obj가 가지고 있는 객체 값이 변경되면 obj도 같은 객체를 가지고 있기 때문에 값이 변경,
즉 원본 데이터의 훼손, 이러한 훼손은 예상치 못한 오류와 버그를 일으킬 수 있다.

이러한 얕은 복사의 에러를 해결하기 위하여 깊은 복사를 실현한다.

  1. spread operator ← (...)
  2. immer와 같은 외부 라이브러리 이용
const [state, setState] = useState([
	{
    	id: 1,
        name: "김성용"
    },
    {
    	id: 2,
        name: "이멜론"
    },
    {
    	id: 3,
        name: "김사과"
    }
])

setState([
	{
    	id: 1,
        name: "김성용"
    },
    {
    	id: 2,
        name: "이멜론"
    },
    {
    	id: 3,
        name: "김사과"
    },
    {
    	id: 4,
        name: "오렌지"
    }
])

이런식으로 하면 에러가 많이 발생한다.
이렇게 하면 얕은 복사다.

그렇다면 object를 값으로 갖고 있는 state의 값을 수정하기 위해서는 어떻게 해애하는가?

  1. setState([...state, {id:4, name: "오렌지"}])
    → 기존의 있던 state 값을 깊은 복사로 가져올 거고 깊은 복사로 가지고 온 state값에 새로운 값을 추가할 것이다.
    이렇게 하면 예기치 못한 에러를 방지할 수 있다. 즉, 깊은 복사를 사용하는 것은 원본 데이터 훼손을 막고자 하는 것이다.

state에 추가


기본적으로 세팅해놓은 것이다. 여기서 입력한 것들을 추가할 수 있다.

주석에서 보면 알 수 있듯이 .map은 for문과 같다. 돌려줘서 배열을 리턴한다.
{user.id}. {user.name}은 userList에서 id와 name을 보여준다.

이제 본격적으로 입력한 것을 추가해주자!


onChange는 변화가 있을 때 적용하는 것인데 입력칸에 뭔가를 적으면 그것이 변화가 된 것이기 때문에 onChangeNameInput이 실행된다. 그러면 기본적으로 useState(""); 공백으로 세팅해준 것이 setName(e.target.value)로 변화된 것 즉, 입력해준 것으로 name이 바뀐다. 그 name이 value={name}이 된 것이다. 하지만 아직 value=name만 바꿔준거지 추가시킬 수는 없다.


여기까지해야 추가할 수 있는데 원래 같으면 const onAddUserList = (id, name) => { 이렇게 해서 인자로 받아야한다. 지금처럼 () =>이렇게 해주면 setUserList([...userList, {id, name}]); id, name 모두 오류가 생긴다. 하지만 지금은 왜 오류가 생기지 않을까?

이 위의 작업에서 name을 작업을 해줘서 따로 써줄 필요는 없다. const [name, setName] = useState(""); 여기 name에서 가져온다. 그러면 id가 없기 때문에 따로 처리해줄 필요가 있다. const id = userList[userList.length -1].id +1로 처리를 해준다. [userList.length -1]이렇게 해준것은 배열의 마지막꺼를 가져오기 위해서다. 마지막꺼를 가져오는 이유는 보통 추가를할 때 마지막꺼에 추가하지 처음꺼나 중간에 추가하면 이상하기 때문이다. [userList.length -1].id +1은 배열의 마지막꺼의 id에 +1을 해준다는 것이다. 예를들어 처음에는 1, 두번째는 2, 세번째는 3 이런식으로 늘어나는 것이다. 그러면 id까지 처리를 해줘서 오류가 생기지 않을 것이다.

추가하기 위해서는 기존의 것을 보여주고 새로운 것도 보여줘야 한다. 그래서 setUserList([...userList, {id, name}]); 이렇게 작성을 해줘서 ...userList로 기존 값을 깊은 복사하고 그 뒤에 위에서 설정한 idinput value={name}으로 객체를 추가해서 바꿔주는 것이다.

setName("");해준 이유는 입력해놓은 글씨를 버튼을 누르면 없애주기 위해서 setName을 공백으로 처리한 것이다.

삭제


버튼을 클릭하면 onRevoeUser(user.id)가 실행되며 user.id가 인자로 넘어가고 =(id) => 이부분에서 인자로 받고 userList.filter((user) => user.id !== id); user.id와 인자로 받은 id(user.id)를 비교해서 같지 않은 것들을 모두 가져온다. 그렇기 때문에 삭제가 된 것이다. 내가 삭제하고 싶은 것에 삭제 버튼을 눌러서 그곳의 user.id가 넘어갔으면 넘어 간것과 기존의 user.id는 같을 것이다. 그래서 같이 않은 것을 모두 가져오게 하면 넘어간 것은 같으므로 조건에 맞지않아서 반환이 되지 않으므로 삭제가 되는 것이다.


useMemo와 useCallback

메모이제이션, 랜더링 최적화

  • 어떤 함수가 생성되거나 해당 값이 연산되는 결과가 오래 걸린다면 리액트가 리랜더링할 때마다 해당 함수를 다시 초기화 후 재선언 해야할 필요가 있는가

  • 물론, 내부 로직이(스코프에 참조된 값이) 수정된다면 다시 호출 해주어야 하지만 값이 바뀌지 않았다면 이전 스테이트와 같은 똑같은 함수를 재선언할 필요가 있는가

→ 재선언할 필요가 없습니다. 따라서 리액트에서는 메모이제이션을 활용하여 재선언 할 필요가 없는 함수를 랜더링이 되더라도 기존의 값을 유지하면서 필요없는 랜더링 시간을 최적화

React.memo, useMemo, useCallback, useRef 등이 있습니다.
최적화에는 비용이 발생하므로 최적화가 필요없는 간단한 로직에는 메모이제이션 x

useMemo

연산된 값을 반환하여 랜더링 되었을 때 재사용이 가능하도록

useCallback

함수를 새로 만들지 않고 랜더링 되었을 때 재사용 할 수 있게 해주는 훅 함수

profile
발전하기 위한 공부

0개의 댓글