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);
แก้ไขข้อผิดพลาดอีกหนึ่งข้อ
