ค้นหาเว็บไซต์

reactjs - ฟังก์ชันสถานะของ zustand เพื่อเปลี่ยนคุณสมบัติหนึ่งของวัตถุ


ดังนั้นฉันกำลังใช้ Zustand กับ React ในแอป Electron ของฉัน ฉันใช้มันเพื่อดึงข้อมูลบางอย่างจากฐานข้อมูล Dexie ซึ่งเป็นเพียงรายการเดียวและบันทึกลงใน state ฉันกำลังพยายามที่จะเรียกใช้ฟังก์ชั่น set จากคอมโพเนนต์ render เพื่อที่จะเปลี่ยนแปลง state ของ property ที่เกี่ยวข้องใน state ใน React useState รหัสนี้ทำงานได้...

setMyState({...appSettings, [val]: data})

แต่ใน zustand สถานะของฉันดูเหมือนแบบนี้และโค้ดนี้ไม่ทำงาน

setAppSettings: (data: unknown, val: string) => {
        set((state) => ({...state.appSettings, [val]: data}))
}

Webstorm กำลังบอกฉันว่า "Argument ของชนิดนี้ไม่สามารถกำหนดให้กับพารามิเตอร์ชนิดนี้ได้" ฉันได้เปลี่ยนชนิดของ "data" เป็น any แล้วแต่ก็ไม่มีผล เมื่อฉันรันโค้ดนี้และคลิกปุ่มเพื่อเปลี่ยนมัน ก็ไม่มีอะไรเกิดขึ้น แม้แต่ข้อผิดพลาด ฉันได้เปลี่ยนโค้ดเป็นแบบนี้แล้วก็ได้ผลลัพธ์เหมือนเดิม, ไม่มีอะไรเกิดขึ้น

setAppSettings: (data: any, val: string) => {
        set((state) => ({
            appSettings: {...state.appSettings, [val]: data}
        }))
},

ด้วยโค้ดที่สองนี้ฉันไม่พบข้อผิดพลาดใน Webstorm ดังนั้นจึงไม่ชัดเจนว่าเกิดอะไรขึ้นเนื่องจากคอนโซลไม่ได้แสดงอะไร นอกจากนี้ สถานะดูเหมือนไม่ถูกอัปเดต ฉันเพิ่มปุ่มที่ console.log วัตถุ 'appSettings' ทั้งหมด และมันยังคงไม่เปลี่ยนแปลง

ฉันรู้สึกว่านี่เป็นวิธีแก้ปัญหาที่ง่าย แต่ฉันพยายามหาทางแก้มันจนหัวแทบชนฝา... มีใครมีความเห็นเรื่องนี้บ้างไหม?

------แก้ไขสำหรับคำตอบแรก ฉันไม่แน่ใจว่าปัญหาอยู่ที่ประเภทของข้อมูลหรือเปล่า? ฉันคิดว่ามันน่าจะเป็นเพราะฉันไม่ค่อยคุ้นเคยกับวิธีการทำงานของ zustand มากกว่า? แต่ฟังก์ชันที่พยายามบันทึกสถานะคือ...

// store.ts
type AppSettings = {
  appSettings: Settings;
  setAppSettings: (role: string, data: unknown) => void;
  getAppSettings: () => void;
}
export const useAppSettings = create<AppSettings>((set) => ({
  appSettings: {
      id: 0,
      sortByTime: false,
      sortByFirstName: false,
      colorMode: '',
      hours: 24,
  },
  setAppSettings: (role: string, data: unknown) => {
      set((state) => ({
          appSettings: {...state.appSettings, [role]: data}
      }))
  },
  getAppSettings: async () => {
      const result = await db.settings.toCollection().first();
      if (result === undefined) {
          console.log("No settings in db, using default")
      } else {
          set(() => ({appSettings: result}))
      }
  },
}))
//Interface for settings object - in another file
export interface Settings {
  id: number,
  sortByTime: boolean,
  sortByFirstName: boolean,
  colorMode: string,
  hours: number,
}

// This buttonCreate function is used to duplicate 4 buttons that 
// all look alike and have the same operation. 

const setSettings = useAppSettings((state) => state.setAppSettings)

const buttonCreate = (forRole: string, con1: any, con2: any) => {
  return (
    <ToggleButtonGroup type="radio" name={forRole} className="mb-2 warning" value={settings[forRole]}>
       <ToggleButton id={forRole + "-toggle-1"} value={con1}
                     className={"btn-dark"} onClick={() => setSettings(forRole, con1)}>
                    {typeof con1 === "boolean" ? "Yes" : con1}
       </ToggleButton>
       <ToggleButton id={forRole + "-toggle-2"} value={con2}
                     className={"btn-dark"} onClick={() => setSettings(forRole, con2)}>
                    {typeof con2 === "boolean" ? "No" : con2}
       </ToggleButton>
    </ToggleButtonGroup>
  )
}

คำตอบ #1

ดังนั้นในกรณีแรก:

setAppSettings: (data: unknown, val: string) => {
        set((state) => ({...state.appSettings, [val]: data}))
}

โดยพื้นฐานสิ่งที่เกิดขึ้นคือ รัฐของคุณมี type บางอย่างเช่น RootState, AppState หรืออะไรก็ตาม

และ

Webstorm is telling me "Argument of type is not assignable to parameter of type". 

ความหมายก็คือ เมื่อคุณมีตัวตั้งค่า [key] แบบนั้น typescript ไม่สามารถแปลง [key:string]: unknown ให้เป็นประเภทของ state ของคุณได้ ดังนั้นมันจึงแจ้งข้อผิดพลาด Argument of type is not assignable

เพื่อหลีกเลี่ยงสิ่งนั้น คุณสามารถเพิ่ม as any ได้ แต่ไม่ใช่กับ data แต่เป็นกับผลลัพธ์ของฟังก์ชัน

setAppSettings: (data: unknown, val: string) => {
        set((state) => ({...state.appSettings, [val]: data} as any))
}

โดยพื้นฐานแล้ว อ็อบเจ็กต์ที่ถูกส่งกลับโดย (state) => ควรเป็น typeof (state)

มีวิธีเลี่ยงอยู่ เช่น การใช้ as const , enums , typeof keyof แต่ต้องการโค้ดของคุณมากกว่านี้เพื่อให้คำตอบที่ถูกต้อง...

อัปเดต

นี่คือข้อผิดพลาดของคุณ:

export type AppSettings = {
  appSettings: Settings;
  setAppSettings: (data: Settings, val: string) => void; // << data: Settings 
  getAppSettings: () => void;
};

// and then you override type:
  setAppSettings: (data: unknown, val: string) => ...

และนี่คือโค้ดที่ทำงานได้:

import { create } from "zustand";
import createSelectors from "./selectors";

export type AppSettings = {
  appSettings: Settings;
  setAppSettings: (data: unknown, val: string) => void;
  getAppSettings: () => void;
};

interface Settings {
  id: number;
  sortByTime: boolean;
  sortByFirstName: boolean;
  colorMode: string;
  hours: number;
}

const appSettings = create<AppSettings>()((set) => ({
  appSettings: {
    id: 1,
    sortByTime: false,
    sortByFirstName: false,
    colorMode: "",
    hours: 0,
  },
  // u also had error here: 
  setAppSettings: (data, val) =>
    set((state) => ({
      ...state, // u need pass state here... 
      appSettings: { ...state.appSettings, [val]: data },
    })),
  getAppSettings: () => {},
}));

export const useAppSettings = createSelectors(appSettings);

แก้ไขข้อผิดพลาดอีกหนึ่งข้อ