fix: 配置组件没有正确同步状态

* 问题出在我应该根据 State 决定组件状态而不是组件状态决定 State
* 踩坑了, 浪费我时间, 唉
This commit is contained in:
CrescentLeaf
2025-10-08 12:24:33 +08:00
parent 38c28c3fb6
commit db43de19c4
5 changed files with 44 additions and 36 deletions

View File

@@ -1,26 +1,26 @@
import React from 'react'
export default class PreferenceStore<T extends object> {
declare value: T
declare setter: React.Dispatch<React.SetStateAction<T>>
declare onUpdate: (value: unknown) => void
declare onUpdate: (value: T) => void
declare state: T
declare setState: React.Dispatch<React.SetStateAction<T>>
constructor() {
const _ = React.useState<T>({} as T)
this.value = _[0]
this.setter = _[1]
const _ = React.useState({} as T)
this.state = _[0]
this.setState = _[1]
}
// 创建一个用于子选项的更新函数
updater(key: string) {
return (value: unknown) => {
const newValue = JSON.parse(JSON.stringify({
...this.value,
createUpdater() {
return (key: string, value: unknown) => {
const newValue = {
...this.state,
[key]: value,
}))
this.setter(newValue)
}
this.setState(newValue)
this.onUpdate?.(newValue)
}
}
setOnUpdate(onUpdate: (value: unknown) => void) {
setOnUpdate(onUpdate: (value: T) => void) {
this.onUpdate = onUpdate
}
}

View File

@@ -0,0 +1,6 @@
import React from 'react'
// deno-lint-ignore no-explicit-any
const PreferenceUpdater = React.createContext<(key: string, value: unknown) => void>(null as any)
export default PreferenceUpdater

View File

@@ -1,18 +1,19 @@
import React from 'react'
import { Dropdown } from 'mdui'
import useEventListener from '../useEventListener.ts'
import PreferenceUpdater from "./PreferenceUpdater.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
icon: string
id: string
disabled?: boolean
updater: (value: unknown) => void
selections: { [id: string]: string }
defaultCheckedId: string
state: string
}
export default function SelectPreference({ title, icon, updater, selections, defaultCheckedId, disabled }: Args) {
const [checkedId, setCheckedId] = React.useState(defaultCheckedId)
export default function SelectPreference({ title, icon, id: preferenceId, selections, state, disabled }: Args) {
const updater = React.useContext(PreferenceUpdater)
const dropDownRef = React.useRef<Dropdown>(null)
const [isDropDownOpen, setDropDownOpen] = React.useState(false)
@@ -30,14 +31,13 @@ export default function SelectPreference({ title, icon, updater, selections, def
{
Object.keys(selections).map((id) =>
// @ts-ignore: selected 确实存在, 但是并不对外公开使用
<mdui-menu-item key={id} selected={checkedId == id ? true : undefined} onClick={() => {
setCheckedId(id)
updater(id)
<mdui-menu-item key={id} selected={state == id ? true : undefined} onClick={() => {
updater(preferenceId, id)
}}>{selections[id]}</mdui-menu-item>
)
}
</mdui-menu>
</mdui-dropdown>
<span slot="description">{selections[checkedId]}</span>
<span slot="description">{selections[state]}</span>
</mdui-list-item>
}

View File

@@ -1,25 +1,27 @@
import { Switch } from 'mdui'
import React from 'react'
import PreferenceUpdater from "./PreferenceUpdater.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
id: string
description?: string
icon: string
updater: (value: unknown) => void
defaultState: boolean
state: boolean
disabled?: boolean
}
export default function SwitchPreference({ title, icon, updater, disabled, description, defaultState }: Args) {
export default function SwitchPreference({ title, icon, id, disabled, description, state }: Args) {
const updater = React.useContext(PreferenceUpdater)
const switchRef = React.useRef<Switch>(null)
React.useEffect(() => {
switchRef.current!.checked = defaultState
}, [defaultState])
switchRef.current!.checked = state
}, [state])
return <mdui-list-item disabled={disabled ? true : undefined} rounded icon={icon} onClick={() => {
switchRef.current!.checked = !switchRef.current!.checked
updater(switchRef.current!.checked)
updater(id, !state)
}}>
{title}
{description && <span slot="description">{description}</span>}

View File

@@ -1,17 +1,18 @@
import React from 'react'
import { prompt } from 'mdui'
import PreferenceUpdater from "./PreferenceUpdater.ts"
interface Args extends React.HTMLAttributes<HTMLElement> {
title: string
description?: string
icon: string
updater: (value: unknown) => void
defaultState: string
id: string
state: string
disabled?: boolean
}
export default function TextFieldPreference({ title, icon, description, updater, defaultState, disabled }: Args) {
const [ text, setText ] = React.useState(defaultState)
export default function TextFieldPreference({ title, icon, description, id, state, disabled }: Args) {
const updater = React.useContext(PreferenceUpdater)
return <mdui-list-item icon={icon} rounded disabled={disabled ? true : undefined} onClick={() => {
prompt({
@@ -19,13 +20,12 @@ export default function TextFieldPreference({ title, icon, description, updater,
confirmText: "确定",
cancelText: "取消",
onConfirm: (value) => {
setText(value)
updater(value)
updater(id, value)
},
onCancel: () => {},
textFieldOptions: {
label: description,
value: text,
value: state,
},
})
}}>