반응형

이번 글에서는 구글 태그 관리자 데이터 레이어 (dataLayer)에 대해 알아보겠습니다.

구글 태그 관리자를 제대로 활용하려면 데이터 레이어를 사용해야 합니다.

사실 조금 어려운 개념입니다. 저도 처음 접했을 때 이해가 잘 되지 않았습니다.

여러분도 처음 들어본 개념이라면 이해가 되지 않으실겁니다. 그래도 끝까지 읽어주세요.

데이터 레이어 = 태그 관리자로 정보를 전달하기 위한 자바스크립트 개체

데이터 레이어는 웹사이트에서 태그 관리자로 정보를 전달하기 위한 자바스크립트 개체입니다.

(자바스크립트란 개발 언어 중 하나이며, 자바 언어와는 별개의 언어입니다 ^^;)

페이지 정보나(페이지 제목, URL) 회원의 구매 정보(결제수단, 상품카테고리) 등을 넣을 수 있습니다.

그리고 그 값을 GTM으로 수집해서 GA에서 분석 용도로 활용할 수 있습니다.

출처 ☞ https://www.analyticsmania.com/post/datalayer-push/#gref

데이터 레이어는 생산성을 200% 높여줍니다.

데이터 레이어는 왜 사용해야 할까요? 데이터 레이어는 구글 도움말 문서를 봐도 사용을 권장하고 있습니다.

좀 더 유연하고 쉽게 GA 구축을 가능하게 해주며 불필요한 개발 리소스가 낭비되지 않게 해줍니다.

아래 자바스크립트가 데이터 레이어 소스 코드 예시입니다. dataLayer.push 영역 다음 부분이 배열입니다.

소스를 살펴보니 userId, weather 등의 정보를 담고 있습니다. GA가 자동으로 수집하지 않는 정보입니다.

때문에 별도로 수집할 필요가 있습니다. dataLayer가 그 역할을 도와준다고 보시면 됩니다.

출처 ☞ 시모 아하바 블로그 (https://www.simoahava.com/analytics/data-layer/)

가급적 개발 소스 상에 삽입하는 방향으로 적용하는 것으로 권장!

데이터 레이어는 GTM에서 맞춤 HTML 기능을 사용해서 삽입할 수 있지만

가급적 개발 소스 상에 데이터 레이어 스크립트를 삽입하는 것을 권장드립니다.

이유는 웹페이지가 리뉴얼이 되거나 일부 영역의 UI가 바뀌게 되면

맞춤 HTML을 활용해서 삽입한 경우 기존 값을 수집하지 못할 수 있기 때문입니다.

앞에서 말씀드린 내용이 이해가 되시나요? 데이터레이어를 한번에 이해하는 것을 어렵습니다.

태그 관리자를 사용하면서 벽에 부딪히는 경우가 바로 데이터레이어 라고 해도 무방합니다.

하지만 데이터레이어를 이해하면 화면 상에 없는 값도 수집할 수 있기 때문에 굉장히 유용합니다.

 

출처: https://entrench-consulting.com/ko/data-tag-management/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%EC%96%B4datalayer%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C%EC%9A%94/#page-content

반응형
반응형

안녕하세요. 
오늘은 React의 custom hooks에 대해 알아보고 직접 만들어보는 시간을 가져보도록 하겠습니다.

Custom hook이란?

요즘 React 개발 트랜드는 react hook을 적극 활용하는 것입니다. hook을 사용함으로 인해 class component 없이도 여러 state 값을 변경해줄 수 있게 되었고, 이는 React 개발자들이 function component를 통한 간결한 코드 작업을 할수있게끔 만들어주었습니다.
useState, useEffect 등등 hook을 사용하는 것만으로도 코드가 훨씬 보기 좋아졌지만, 반복되는 훅 활용 메소드들을 하나로 줄여줌으로써 더 간결하고 보기 좋은 코드를 만들 수 있는 것이 바로 custom hooks입니다. 이름에서 알 수 있다시피 custom hook은 개발자 본인이 직접 hook을 만드는 것이죠.

그렇지만 중요한 포인트가 있습니다. custom hook의 이름은 무조건!!!! use로 시작해야합니다. 이 점은 꼭 유념해주셔야 합니다.

사용 예제 코드

custom hooks 적용 전

Jsonplaceholder API를 사용하여 간단하게 구현해보도록 하겠습니다.
우선 UserList, UserDetail 컴포넌트를 생성했습니다. Jsonplaceholder에서 유저정보 10개를 받아 리스트로 보여주고 유저이름을 클릭하면 UserDetail page로 이동하는 아주 간단한 예제입니다.

//UserList.js

import React, { useEffect, useState } from "react"
import { Link } from "react-router-dom"

function UserList() {
  const [userList, setUserList] = useState([])
  const url = "https://jsonplaceholder.typicode.com/users"

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(resJson => setUserList(resJson))
  }, [])

  return userList.map(user => (
    <Link
      to={`/${user.id}`}
      key={user.id}
      className="list-group-item list-group-item-action"
    >
      <div>{user.name}</div>
    </Link>
  ))
}

export default UserList
//userDetail

import React, { useEffect, useState } from "react"
import { useParams } from "react-router-dom"

function UserDetail(props) {
  const [userInfo, setUserInfo] = useState([])
  const { id } = useParams()
  const url = `https://jsonplaceholder.typicode.com/users/${id}`

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(resJson => setUserInfo(resJson))
  }, [])

  return (
    <div>
      {userInfo.name}
      <br />
      {userInfo.email}
      <br />
      {userInfo.phone}
    </div>
  )
}

export default UserDetail

hook을 이용하여 쉽게 구현하였지만 아쉬움이 남습니다. 두 컴포넌트에서 data를 받아오는 useEffect 내의 fetch함수 부분이 똑같기 때문에 이를 하나로 통일시키고 싶습니다. 그럴때 우리는 custom hooks를 통해 이를 해결할 수 있습니다.

custom hook 적용해보기

두 컴포넌트의 fetch함수를 useFetch라는 hook을 만들어서 통일시켜주도록 하겠습니다.
우선 hooks라는 디렉토리를 만든 후 useFetch.js를 만들어줍니다.

hooks 디렉토리를 꼭 만들어야하나요?

꼭 그래야 하는 것은 아니지만 나중에 custom hooks가 많아진다면 디렉토리 구조가 복잡해지겠죠?? 그럴때를 대비해서 hooks 디렉토리를 만들어 놓는 것이 보기 좋고 그때그때 꺼내서 사용하기도 편리합니다.

그럼 useFetch.js 내 코드를 작성해보도록 하겠습니다.

//useFetch.js

import { useEffect, useState } from "react"

function useFetch(url) {
  const [data, setData] = useState([])

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(resJson => setData(resJson))
  }, [url])

  return data
}

export default useFetch

UserList,UserDetail 컴포넌트에서 겹쳤던 fetch부분을 그대로 넣어주고 data를 return 해주면 끝입니다. url을 인자로 받고 해당 url을 useEffect의 의존성 배열로 넣어주면 custom hook이 원할때 잘 호출되겠죠?? 이제 UserList, UserDetail 컴포넌트가 어떻게 변경할 수 있는지 살펴볼까요??

custom hooks 적용 후

//UserList.js

import React from "react"
import { Link } from "react-router-dom"
import useFetch from "./hooks/useFetch"

function UserList() {
  const userList = useFetch("https://jsonplaceholder.typicode.com/users") 

  return userList.map(user => (
    <Link
      to={`/${user.id}`}
      key={user.id}
      className="list-group-item list-group-item-action"
    >
      <div>{user.name}</div>
    </Link>
  ))
}

export default UserList
//UserDetail.js

import React from "react"
import { useParams } from "react-router-dom"
import useFetch from "./hooks/useFetch"

function UserDetail(props) {
  const { id } = useParams()
  const userInfo = useFetch(`https://jsonplaceholder.typicode.com/users/${id}`)

  return (
    <div>
      {userInfo.name}
      <br />
      {userInfo.email}
      <br />
      {userInfo.phone}
    </div>
  )
}

export default UserDetail

어떤가요?? 단 한줄로 useEffect와 useState 그리고 fetch 함수를 대체할 수가 있어졌습니다. 이전 코드보다 훨씬 간단해졌고 custom hooks의 네이밍이 잘되어있다는 가정하에 코드 가독성도 훨씬 높아지지 않았나요?? 지금은 fetch함수를 사용하는 component가 2개밖에 없지만 fetch함수를 사용하는 컴포넌트가 더 많으면 많을 수록 우리의 custom hooks는 그 힘을 발휘할 것입니다 ㅎㅅㅎ

마무리

이렇게 컴포넌트 로직을 뽑아내서 정의한 후 간편하게 호출할 수 있다는 것이 custom hooks의 정말 큰 장점이 아닐까 생각이됩니다.
이 밖에도 여러개의 input들이 존재하고 각각 여러개의 state 값을 control할 때에도 useInput이라는 custom hooks를 사용하여 코드를 간단하게 만들 수 있을겁니다. 아니면 user 정보를 useAuth라는 custom hooks를 만들어 그때그때 편하게 호출할 수도 있겠죠?
custom hooks를 좋은 네이밍과 더불어 사용하면 코드의 가독성을 높이고 짧고 간결한 코드를 작성할 수가 있을겁니다.

 

출처: https://velog.io/@kysung95/%EC%A7%A4%EB%A7%89%EA%B8%80-Custom-Hooks%EC%9D%84-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90

반응형

'Web > Js' 카테고리의 다른 글

Nuxt js dot env 적용하기 (자체 cross-env 적용기)  (0) 2022.05.12
데이터레이어(dataLayer)란 무엇일까?  (0) 2022.03.18
useCallback 과 useMemo 의 차이  (0) 2022.03.16
componentDidUpdate  (0) 2022.03.04
package-lock.json이란?  (0) 2022.02.24
반응형

 


먼저 메모이제이션(memoization) 이란?

 

useMemo 함수에 대해서 알아보기 전에 알고리즘 시간에 자주 나오는 메모이제이션(memoization) 개념에 대해서 잠깐 짚는다.

memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말한다. 

memoization을 절적히 적용하면 중복 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 애플리케이션의 성능을 최적화할 수 있다.

 

useMemo와 useCallback 을 너무나도 어렵게 설명하는 곳이 많아서 여기서는 간단하게만 적어본다.

 


1. useMemo

 

메모이제이션된 ''을 반환한다.


  • 용법
useMemo(() => fn, deps)

 

⭐️ useMemo 는 deps 가 변한다면, () => fn 이라는 함수를 실행하고 그 값을 반환한다. ⭐️

deps 는 dependency이며, useMemo가 이 deps라는 것에 '의존'한다는 뜻이다.

 

  • 예시
import React, { useState, useCallback, useMemo } from "react";

export default function App() {
  const [ex, setEx] = useState(0);
  const [why, setWhy] = useState(0);

  // useMemo 사용하기
  useMemo(() => {console.log(ex)}, [ex]);

  // 두 개의 버튼을 설정했다. X버튼만이 ex를 변화시킨다.
  return (
    <>
      <button onClick={() => setEx((curr) => (curr + 1))}>X</button>
      <button onClick={() => setWhy((curr2) => (curr2 + 1))}>Y</button>
    </>
  );
}

 

 

이런 작고 소중한 버튼이 있다.

먼저 위 코드는 X라는 버튼을 누를 때에 'ex' 라는 상태값이 변화하는 코드이다.

 

useMemo(() => {console.log(ex)}, [ex]) 

 

에서 deps 는 [ex] 이다.

ex 가 변할 때에만 () => {console.log(ex)} 이 실행된다.

 

따라서 X 버튼을 누를 때에만 콘솔창에 ex 값이 출력된다.

Y 버튼을 누르더라도 APP 이라는 함수 컴포넌트가 전부 재실행 되지만,

ex 라는 값은 변하지 않았기 때문에 useMemo는 에는 아무런 변화가 없다.

 


2. useCallback

 

메모이제이션된 '함수'를 반환한다.

 

 

이 친구가 useMemo 보다 어렵다. useMemo 는 그냥 함수를 실행해버리는데, 얘는 함수를 반환한다.

 

useCallback(fn, deps)

 

useCallback  deps 가 변한다면, fn 이라는 새로운!함수를 반환한다.

 

import React, { useState, useCallback, useMemo } from "react";

export default function App() {
  const [ex, setEx] = useState(0);
  const [why, setWhy] = useState(0);

  // useCallback 이 () => {console.log(why)} 라는 함수를 반환한다.
  const useCallbackReturn = useCallback(() => {console.log(why)}, [ex]);

  // useCallback 이 담겨있는 함수를 실행
  useCallbackReturn()

  return (
    <>
      <button onClick={() => setEx((curr) => (curr + 1))}>X</button>
      <button onClick={() => setWhy((curr2) => (curr2 + 1))}>Y</button>
    </>
  );
}

 

아까 그 코드와 같은 버튼을 보여주는 코드이다.

위의 useCallback  () => {console.log(why)} 라는 함수를 반환해주고 있다.

 

위의 useCallback 은 다음의 순서로 진행될 것이다.

 

  1. 처음 컴포넌트가 시작될 때 실행 () => {console.log(0)}
  2. ex 가 변할 때까지 함수는 () => {console.log(0)}
  3. ex 가 변한다면 그제서야 why 의 값을 가져와서 () => {console.log(새로운 값)}

 

예를 들어서 Y 버튼을 다섯번 누른다고 해보자.

Y 버튼이 눌리면 'why'라는 상태의 값이 1씩 증가할 것이다.

 

 

위의 움짤에서 보듯이, Y를 다섯번 누를 때 동안에는 계속 함수가 () => {console.log(0)} 이다.

(물론 이 때 why라는 상태값은 계속 값이 증가한다.)

그러다가 X 버튼을 누르면서 ex 라는 변수(deps) 가 변하자 마자, () => {console.log(5)} 를 반환한다.

deps가 변해야 함수 컴포넌트와 상태값(why) 를 공유하는 것이다!!

 

따라서 useCallback 은 함수와는 상관 없는 상태값이 변할 때,

함수 컴포넌트에서 불필요하게 함수를 업데이트 하는 것을 방지해준다.

 

다만, deps 를 잘못 설정하면 아무리 함수 컴포넌트를 재실행해도 함수가 변하지 않으면서

내가 원치 않는 상황이 올 수도 있으므로 섬세한 컨트롤이 필요하다..

 

이런 상황은 useMemo도 똑같다. useMemo 역시 Y 버튼을 5번 눌러도, X버튼을 안 누르면 실행이 되지 않는다.

 

추가로, react 공식 문서에서도 인정하듯이, 아래의 두 식은 같다.

 

useMemo((...)=>fn, deps) === useCallback(fn, deps)

 


3. useCallback 의 새로고침

 

useCallback 은 deps 가 변하면서 함수를 반환할 때, 형태가 같더라도 아예 새로운 함수를 반환한다.

 

const add1 = () => {};
const add2 = () => {};

 

위 두 함수는 같은가?

 

답은 두 함수는 전혀 같지 않다.

 

 

각 변수는 같은 함수를 바라볼 뿐 전혀 다른 변수이다.

바라보는 값만 같을 뿐, 전혀 다른 메모리를 가진 변수이다.

 


useCallback 은  새로운 함수를 반환한다

 

const useCallbackReturn = useCallback(() => {}, [ex])

 

여기서 ex 가 변할 때, useCallback 은 새로운 함수를 반환한다.

그 말은 즉, ex == 0 일 때와 ex == 1 일 떄의 () => {} 은 다른 함수다.

새로운 무기명 함수를 반환했기 때문이다. 이는 앞서 기술했듯이, 값이 같을 뿐 다른 메모리이다.

 

출처: https://basemenks.tistory.com/238

반응형

'Web > Js' 카테고리의 다른 글

데이터레이어(dataLayer)란 무엇일까?  (0) 2022.03.18
Custom Hooks을 만들어보자!  (0) 2022.03.17
componentDidUpdate  (0) 2022.03.04
package-lock.json이란?  (0) 2022.02.24
[Vue.JS] Vuex Store를 바인딩하는 4가지 방법  (0) 2022.02.22
반응형

componentDidUpdate(prevProps, prevState)

< Props Update >

props가 업데이트될 때의 과정입니다. 업데이트되기 전에 업데이트가 발생하였음을 감지하고, componentWillReceiveProps 메소드가 호출됩니다. 그 후 shouldComponentUpdate, componentWillUpdate가 차례대로 호출된 후, 업데이트가 완료(render)되면 componentDidUpdate가 됩니다.
이 메소드들은 첫 번째 인자로 바뀔 props에 대한 정보를 가지고 있습니다. componentDidUpdate만 이미 업데이트되었기 때문에 바뀌기 이전의 props에 대한 정보를 가지고 있습니다.

componentDidUpdate(prevProps, prevState) { // 이전 props, state에 대한 정보
    if (prevProps.todos.length !== this.props.todos.length) {
      // 이전 todo리스트의 길이가 달라지면(추가,삭제) 상태변화
      this.setState({
        dataSource: this.state.ds.cloneWithRowsAndSections(
          _.groupBy(this.props.todos, 'createdAt'),
        ),
      })
    }
    if (prevState.isTodoList !== this.state.isTodoList) {
      // 탭 이동
      if (!this.state.isTodoList) { // 완료된 탭일 때,
        this.setState({ // 완료된 탭만 필터된 datasource
          dataSource: this.state.ds.cloneWithRowsAndSections(
            _.groupBy(_.filter(this.props.todos, (todo) => todo.isDone), 'createdAt'),
          ),
        })
      } else {
        this.setState({
          dataSource: this.state.ds.cloneWithRowsAndSections(
            _.groupBy(this.props.todos, 'createdAt'),
          ),
        })
      }
    }
  }

 

참고링크
https://www.zerocho.com/category/React/post/579b5ec26958781500ed9955

 

출처: https://feel5ny.github.io/2017/12/23/log_002/

반응형

'Web > Js' 카테고리의 다른 글

Custom Hooks을 만들어보자!  (0) 2022.03.17
useCallback 과 useMemo 의 차이  (0) 2022.03.16
package-lock.json이란?  (0) 2022.02.24
[Vue.JS] Vuex Store를 바인딩하는 4가지 방법  (0) 2022.02.22
React 컴포넌트에 함수 전달하기  (0) 2022.02.15

+ Recent posts