[React]상태 관리 라이브러리(zustand)

rondido·2022년 12월 9일
0

React

목록 보기
37/39
post-thumbnail

zustand 설치하기

 npm install zustand

zustand 시작하기

button click text가 커지는 component 생성

Text.jsx

import React from 'react'
import create from 'zustand';

const useStore = create((set)=>({
  fontSize : 14,
  increaseFontSize:() => set((state)=>({fontSize:state.fontSize +1}))

}));

export default function Text() {
    const fontSize = useStore((state)=> state.fontSize);    
    const increaseFontSize = useStore((state)=> state.increaseFontSize);       
  return (
    <>
      <p style={{fontSize}}>This text will increase in size too.</p>
      <button onClick={increaseFontSize}>size up</button>
    </>
  )
}

set을 create로 만들어 진 값을 업데이트 할 수 있다.

Text.jsx

import React from 'react';
import create from 'zustand';

const useStore = create((set)=>({
  fontSize : 14,
  increaseFontSize:() => set((state)=>({fontSize:state.fontSize +1})),
  trigger:false,
  toggleTrigger:()=>set((state)=>({trigger:!state.trigger})),
}));

function FontLabel() {
  const{fontSize,increaseFontSize,fontSizeLabel} = useStore((state)=>({
    fontSize:state.fontSize,
    increaseFontSize:state.increaseFontSize,
    fontSizeLabel:state.fontSize + "px",

  }))
  return (
    <>
      <div style={{fontSize}}>Current font size: {fontSizeLabel}</div>
      <button onClick={increaseFontSize}>size up</button>
    </>
  )
}

export default function Text() {
    const fontSize = useStore((state)=> state.fontSize);    
    
  return (
    <>
      <p style={{fontSize}}>This text will increase in size too.</p>
      <FontLabel/>
    </>
  )
}

2가지 컴포넌트가 분리 되어 있지만 두가지의 state가 연결되어잇는 것을 볼 수 있다.

import React from 'react';
import create from 'zustand';

const useStore = create((set)=>({
  fontSize : 14,
  increaseFontSize:() => set((state)=>({fontSize:state.fontSize +1})),
  trigger:false,
  toggleTrigger:()=>set((state)=>({trigger:!state.trigger})),
}));

function FontLabel() {
  const{fontSize,increaseFontSize,fontSizeLabel,trigger,toggleTrigger} = 
  useStore((state)=>({
    fontSize:state.fontSize,
    increaseFontSize:state.increaseFontSize,
    fontSizeLabel:state.fontSize + "px",
    trigger:state.trigger,
    toggleTrigger:state.toggleTrigger,
  }),
  (oldState,newState)=>oldState.trigger === newState.trigger)
  return (
    <>
      <div style={{fontSize}}>Current font size: {fontSizeLabel}</div>
      <button onClick={increaseFontSize}>size up</button>
      <button onClick={toggleTrigger}>toggle: {trigger.toString()}</button>
    </>
  )
}

export default function Text() {
    const fontSize = useStore((state)=> state.fontSize);    
    
  return (
    <>
      <p style={{fontSize}}>This text will increase in size too.</p>
      <FontLabel/>
    </>
  )
}

useStore에 2번째로 인자로 비교 함수를 넣어서 업데이트에 관련된 state를 관리할 수 있다.

sizeup을 누르면 text의 크기가 변하지만 밑에 text의 px값을 변하지 않는다. 하지만
trigger를 통해 trigger가 변경이 일어 났을때 (즉,toggle버튼을 true로 바꿈으로써) 밑에 px의 값이 변한 것을 알 수 있다.

CharacterCount.jsx

import React from 'react'
import create from 'zustand';

const useStore = create((set)=>({
  textState:"",
  setTextState:(text)=>set(()=>({textState:text})),
}))

export default function CharacterCounter() {
  return (
    <div>
        <TextInput/>
        <CharacterCount/>
    </div>
  )
}

function TextInput(){
  const [text,setText] = useStore((state)=>[
    state.textState,
    state.setTextState,
  ]);

  const onChange = (event) =>{
    setText(event.target.value);
  }
  return(
    <div>
        <input type="text" value={text} onChange={onChange}/>
        <br/>
        Echo:{text}
    </div>
  )
}

function CharacterCount(){
  const count = useStore((state)=>state.textState.length);

  return <>Character Count:{count}</>
}


zustands devtools

import create from "zustand";
import { devtools } from "zustand/middleware";

export const useStore = create(
  devtools((set, get) => ({
    todoListState: [],
    setTodoListState: (list) => set({ todoListState: list }),
    todoListFilterState: "Show All",
    settodoListFilterState: (filter) => set({ todoListFilterState: filter }),
    filteredTodoListState: () => {
      const filter = get().todoListFilterState;
      const list = get().todoListState;

      switch (filter) {
        case "Show Completed":
          return list.filter((item) => item.isComplete);
        case "Show Uncompleted":
          return list.filter((item) => !item.isComplete);
        default:
          return list;
      }
    },
    todoListStatsState: () => {
      const todoList = get().todoListState;
      const totalNum = todoList.length;
      const totalCompletedNum = todoList.filter(
        (item) => item.isComplete
      ).length;
      const totalUncompletedNum = totalNum - totalCompletedNum;
      const percentCompleted =
        totalNum === 0 ? 0 : totalCompletedNum / totalNum;

      return {
        totalNum,
        totalCompletedNum,
        totalUncompletedNum,
        percentCompleted,
      };
    },
  }))
);


useStore뒤에 devtools 선언후 ()를 감싸주면 됨.

redux-devtools로 상태값들을 확인할 수 있다.

Data fetching

import axios from 'axios';
import React from 'react'
import { useEffect } from 'react';
import create from 'zustand';



const useStore = create((set,get)=>({
    id:2,
    setId:(id) =>set({id:id}),
    userName:"park",
    fetchUserName:async()=>{
        const response = await axios.get(
            `/api/user-name?id=${get().id}`
        );        
        set({useName:response.data.name});
    }
}))
function CurrentUser() { 
    const userName = useStore(state=>state.useName);    
    
   
    return <div>{userName}</div>;
}

export default function CureentUserInfo(){
    const [id, setId] = useStore(state=>[state.id,state.setId]);
    const fetchUserName = useStore(state=>state.fetchUserName);

    useEffect(()=>{
        fetchUserName();
    },[id])
    return (
        <>
            <CurrentUser/>
            <input value={id} onChange={(e)=>setId(e.target.value)}/>
        </>
    )
}


profile
개발 옆차기

0개의 댓글