Zustand - useShallow

Hunter Joe·2024년 12월 15일
0

각 코드의 비교를 통한 shallow를 알아보려고 한다.
console.log()로 어느 컴포넌트가 렌더링 되는지 확인 바랍니다

혹시라도 더 정확한 설명을 댓글로라도 알려주시면 감사하겠습니다.

📌1.기존 zustand 코드

import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";

const useStore = create((set) => ({
	name: "John",
	age: 30,
	address: "123 Main St",
	setName: (name) => set({ name }),
	setAge: (age) => set({ age }),
	setAddress: (address) => set({ address }),
}));

const UserInfo = () => {
  const name = useStore((state) => state.name);
  const age = useStore((state) => state.age);
	
  return (
	<div>
	  <p>Name: {name}</p>
	  <p>Age: {age}</p>
	</div>
	);
};

const Address = () => {
  const address = useStore((state) => state.address);
  console.log(address);
  return <div>Address: {address}</div>;
};

const App = () => {
  const setName = useStore((state) => state.setName);
   const setAge = useStore((state) => state.setAge);
   const setAddress = useStore((state) => state.setAddress);

	console.log("app Rendered");
	return (
	   <div>
		<UserInfo />
		<Address />
		<button onClick={() => setName("Jane")}>Change Name</button>
		<button onClick={() => setAddress("Wall.St")}>Change Address</button>
		<button onClick={() => setAge(31)}>Change Age</button>
	  </div>
	);
};

export default App;

console.log() 결과 찍어보기

changeName, changeAge 실행

userInfo컴포넌트 리렌더

changeAddress 실행

Address컴포넌트 리렌더

📌2.구조 분해 할당 코드(권장X)

코드량을 줄어들었지만 어떤 일이 생기는지 보자.

//...useStore는 변경점 없음

const UserInfo = () => {
  const { name, age } = useStore();
  console.log(name);
  console.log(age);

	return (
	  <div>
		<p>Name: {name}</p>
		<p>Age: {age}</p>
	  </div>
	);
};

const Address = () => {
  const address = useStore((state) => state.address);
  console.log(address);
  return <div>Address: {address}</div>;
};

const App = () => {
  const { setName, setAge, setAddress } = useStore();

  console.log("app Rendered");
  return (
  <div>
    <UserInfo />
	  <Address />
	  <button onClick={() => setName("Jane")}>Change Name</button>
	  <button onClick={() => setAddress("Wall.St")}>Change Address</button>
	  <button onClick={() => setAge(31)}>Change Age</button>
	</div>
	);
};

export default App;

changeName, changeAge, changeAddress 실행

구조 분해 할당으로 빼오면 모든 컴포넌트가 동일하게 리렌더링이 일어남 (권장X)
userInfo, Address컴포넌트 리렌더

구조 분해 할당은 안쓰는게 맞는거 확인.
특정 케이스로 쓰는경우는 있겠지만 되도록 안쓰는게 좋아보임

📌3.useShallow를 쓴 코드

//... useStore는 변경점 없음
import { useShallow } from "zustand/react/shallow";

const UserInfo = () => {
  const { name, age } = useStore(
	useShallow((state) => ({ name: state.name, age: state.age })),
	);
  console.log(name);
  console.log(age);

  return (
	<div>
	  <p>Name: {name}</p>
	  <p>Age: {age}</p>
	</div>
  );
};

const Address = () => {
	const address = useStore((state) => state.address);
	console.log(address);
	return <div>Address: {address}</div>;
};

const App = () => {
  const { setName, setAge, setAddress } = useStore(
    useShallow((state) => ({
	  setName: state.setName,
	  setAge: state.setAge,
	  setAddress: state.setAddress,
	})),
  );

  console.log("app Rendered");
  return (
    <div>
	  <UserInfo />
	  <Address />
	  <button onClick={() => setName("Jane")}>Change Name</button>
	  <button onClick={() => setAddress("Wall.St")}>Change Address</button>
	  <button onClick={() => setAge(31)}>Change Age</button>
	</div>
  );
};

export default App;

changeName, changeAge 실행

userInfo컴포넌트 리렌더

changeAddress 실행

Address컴포넌트 리렌더

useShallow를 쓰면 📌1과 동일하게 작동한다.(신기방기)
이렇게 해서 불필요한 렌더링을 줄이는구나!

내가 찾은건 여기까지 shallow를 쓰면 구조 분해 할당으로 가져올 수 있고
해당 객체를 참조하는 방법이 얕은 복사로 달라진다.

전체 코드

  • 혹시 테스트 해보고싶으신 분들을 위해 남김
import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";

const useStore = create((set) => ({
	name: "John",
	age: 30,
	address: "123 Main St",
	setName: (name) => set({ name }),
	setAge: (age) => set({ age }),
	setAddress: (address) => set({ address }),
}));

const UserInfo = () => {
	const { name, age } = useStore(
		useShallow((state) => ({ name: state.name, age: state.age })),
	);
	/**
	 *
	 */
	// 기존
	// const name = useStore((state) => state.name);
	// const age = useStore((state) => state.age);

	// 구조 분해 할당
	// const { name, age } = useStore();

	console.log(name);
	console.log(age);

	return (
		<div>
			<p>Name: {name}</p>
			<p>Age: {age}</p>
		</div>
	);
};

const Address = () => {
	const address = useStore((state) => state.address);
	console.log(address);
	return <div>Address: {address}</div>;
};

const App = () => {
	// 기존 코드
	// const setName = useStore((state) => state.setName);
	// const setAge = useStore((state) => state.setAge);
	// const setAddress = useStore((state) => state.setAddress);

	// 구조 분해 할당
	// const { setName, setAge, setAddress } = useStore();

	const { setName, setAge, setAddress } = useStore(
		useShallow((state) => ({
			setName: state.setName,
			setAge: state.setAge,
			setAddress: state.setAddress,
		})),
	);

	console.log("app Rendered");
	return (
		<div>
			<UserInfo />
			<Address />
			<button onClick={() => setName("Jane")}>Change Name</button>
			<button onClick={() => setAddress("Wall.St")}>Change Address</button>
			<button onClick={() => setAge(31)}>Change Age</button>
		</div>
	);
};

export default App;
profile
Async FE 취업 준비중.. Await .. (취업완료 대기중) ..

0개의 댓글