카테고리 없음

Zus(tand) 한 잔 할래요?

박강원입니다 2025. 3. 27. 14:51

이 익스텐션 2개 설치했습니다.

 

tsrafce

import React from 'react'

type Props = {}

const page = (props: Props) => {
  return (
    <div>page</div>
  )
}

export default page

usf

const [, set] = useState();

uef

useEffect(() => {
  
}, []);

 

 

ZUSTAND 설치법

yarn add zustand

 

 

/src/app/zustand 폴더 생성 후 page.tsx 생성

import { create } from 'zustand'

type Props = {}

interface TestStore {
  count: number;
  increment: () => void;
  decrement: () => void;
}

//zustand는 전역 상태 관리 라이브러리

const useTestStore = create<TestStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 }))
}));

export default useTestStore

 

 

 

import { create } from 'zustand'

type Props = {}

interface TestStore {
  count: number;
  increment: () => void;
  decrement: () => void;
}

//zustand는 전역 상태 관리 라이브러리

const useTestStore = create<TestStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 }))
}));

const ZustandTestPage = (props: Props) => {
  const { count, increment, decrement } = useTestStore();
  //useShallow로 사용하는 방법 찾아서 적용해보기
  //useShallow 쓰는 이유 찾아보기
  return (
    <div className="flex gap-2 items-center">
      <div>{count}</div>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

export default ZustandTestPage;

 

 

useShallow 사용!! 

 

import { create } from 'zustand'
import { shallow } from 'zustand/shallow'


type Props = {}

interface TestStore {
  count: number;
  increment: () => void;
  decrement: () => void;
}

//zustand는 전역 상태 관리 라이브러리

const useTestStore = create<TestStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 }))
}));

const ZustandTestPage = () => {
  // useShallow를 사용하는 방법 1: 객체 선택자와 함께 사용
  // const { count, increment, decrement } = useTestStore(
  //   (state) => ({
  //     count: state.count,
  //     increment: state.increment,
  //     decrement: state.decrement
  //   }),
  //   shallow
  // );

  // useShallow를 사용하는 방법 2: 개별 선택자 사용 (권장)
  const count = useTestStore((state) => state.count);
  const increment = useTestStore((state) => state.increment);
  const decrement = useTestStore((state) => state.decrement);

  return (
    <div className="flex gap-2 items-center">
      <div>{count}</div>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

export default ZustandTestPage;

 

useShallow를 쓰는 이유

1. 불필요한 리렌더링 방지

- 매번 새로운 객체가 생성되어 리렌더링 발생

- 얕은 비교를 통해 실제 값이 변경되었을 때만 리렌더링

2. 성능 최적화

- 객체의 얕은 비교를 수행

- 실제로 값이 변경되었을 때만 리렌더링 

- 메모리 사용량 감소

3. 메모리 효율성

-불필요한 객체 생성 방지

- 가비지 컬렉션 부하 감소

4. 예측 가능한 동작

- 상태 업데이트 시 컴포넌트의 리렌더링 시점을 더 정확하게 제어 가능

- 디버깅이 용이

 

 

터미널에 아래 코드 쳐서 다운로드 했습니다.

yarn add zod
yarn add react-hook-form

 

 

아예 싹 지우고 다시 작성함

'use client'
import { create } from 'zustand'
import { shallow } from 'zustand/shallow'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'

const ZodTestPage = () => {
  const schema = z.object({
    name: z.string().min(1, "이름은 2글자 이상으로 적어주세요"),
    email: z.string().email("이메일 양식이 올바르지 않습니다."),
  });

  const form = useForm<z.infer<typeof schema>>({
    resolver: zodResolver(schema),
    defaultValues: {
      name: "",
      email: "",
    }
  });

  const onSubmit = (values: z.infer<typeof schema>) => {
    console.log(values);
  };

  return (
    <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-2 p-4">
      <input 
        type='text' 
        {...form.register("name")}
        placeholder="이름"
        className="border p-2 rounded"
      />
      {form.formState.errors.name && (
        <p className="text-red-500">{form.formState.errors.name.message}</p>
      )}
      
      <input 
        type='text' 
        {...form.register("email")}
        placeholder="이메일"
        className="border p-2 rounded"
      />
      {form.formState.errors.email && (
        <p className="text-red-500">{form.formState.errors.email.message}</p>
      )}
      
      <button 
        type='submit'
        className="bg-blue-500 text-white p-2 rounded hover:bg-blue-600"
      >
        제출
      </button>
    </form>
  );
}

export default ZodTestPage;