From 818c6025f4b5c77802298e859670459dd53c4bb6 Mon Sep 17 00:00:00 2001 From: thzxx <1440196015@qq.com> Date: Sun, 13 Sep 2026 13:04:10 +0800 Subject: [PATCH] =?UTF-8?q?0.1.39=20P1:=20MemberCard=20memo=20=E5=8C=96=20?= =?UTF-8?q?+=20FamilyPanel=20useMemo=20=E6=8E=92=E5=BA=8F=E7=BC=93?= =?UTF-8?q?=E5=AD=98=EF=BC=88=E8=84=B1=E7=A6=BB=20store=20=E8=AE=A2?= =?UTF-8?q?=E9=98=85=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/ui/components/MemberCard.tsx | 46 +++++++++++++---------- src/renderer/ui/panels/FamilyPanel.tsx | 35 +++++++++-------- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/renderer/ui/components/MemberCard.tsx b/src/renderer/ui/components/MemberCard.tsx index 28a5fda..37f94ca 100644 --- a/src/renderer/ui/components/MemberCard.tsx +++ b/src/renderer/ui/components/MemberCard.tsx @@ -1,4 +1,4 @@ -import { useGameStore } from '../store' +import { memo } from 'react' import { Character } from '../../game/types/domain' import { describeRealm } from '../../game/data/realms' import { describeRoots } from '../../game/data/elements' @@ -13,18 +13,34 @@ const STATE_LABEL: Record = { dead: { label: '已殁', cls: 'bad' } } -export function MemberCard({ c }: { c: Character }) { - const world = useGameStore((s) => s.world) - const setSelected = useGameStore((s) => s.setSelected) - if (!world) return null +const C_STATE: Record = { + idle: '', + meditation: 'good', + expedition: 'warn', + wounded: 'bad', + dead: 'bad' +} + +/** + * 0.1.39 渲染提效:MemberCard 改为 memo 纯展示组件—— + * 不再从 store 获取 world(之前每次 revision bump 全部卡片重渲染)。 + * 所需外部数据(surname/isHead/age)经 props 传入,只在 c 或依赖 props 变化时重渲染。 + */ +export interface MemberCardProps { + c: Character + surname: string + isHead: boolean + age: number + onSelect: (id: string) => void +} + +export const MemberCard = memo(function MemberCard({ c, surname, isHead, age, onSelect }: MemberCardProps) { const dead = !c.alive - const isHead = world.state.family.headId === c.id - const state = STATE_LABEL[dead ? 'dead' : c.state] const blocked = !dead && c.realmProgress >= 100 && c.realm.major !== 'spirit' return ( -
setSelected(c.id)}> +
onSelect(c.id)}>
-
{world.state.family.surname}
+
{surname}
{c.name} @@ -34,7 +50,7 @@ export function MemberCard({ c }: { c: Character }) {
{dead ? `殁于${c.deathYear}年 · ${c.deathCause ?? '寿终'}` - : `${describeRealm(c.realm)} · ${world.ageOf(c)}岁 · 修为${Math.floor(c.realmProgress)}%`} + : `${describeRealm(c.realm)} · ${age}岁 · 修为${Math.floor(c.realmProgress)}%`}
@@ -55,12 +71,4 @@ export function MemberCard({ c }: { c: Character }) { )}
) -} - -const C_STATE: Record = { - idle: '', - meditation: 'good', - expedition: 'warn', - wounded: 'bad', - dead: 'bad' -} +}) diff --git a/src/renderer/ui/panels/FamilyPanel.tsx b/src/renderer/ui/panels/FamilyPanel.tsx index f328e5d..40bc3b0 100644 --- a/src/renderer/ui/panels/FamilyPanel.tsx +++ b/src/renderer/ui/panels/FamilyPanel.tsx @@ -1,4 +1,5 @@ import { useGameStore } from '../store' +import { useMemo } from 'react' import { MemberCard } from '../components/MemberCard' import { MemberModal } from '../components/MemberModal' import { Character } from '../../game/types/domain' @@ -11,25 +12,29 @@ export default function FamilyPanel() { void revision if (!world) return null const s = world.state - const alive = Object.values(s.members).filter((c) => c.alive) - const dead = Object.values(s.members).filter((c) => !c.alive) - const sorted = [...alive].sort((a, b) => { - const aHead = a.id === s.family.headId ? -1 : 0 - const bHead = b.id === s.family.headId ? -1 : 0 - return aHead - bHead || world.ageOf(b) - world.ageOf(a) - }) - const selected = selectedMemberId ? s.members[selectedMemberId] as Character | undefined : undefined - - const marriageReady = (() => { - if (!world) return [] - return alive.filter( + const surname = s.family.surname + const headId = s.family.headId + const { alive, dead, sorted, marriageReady } = useMemo(() => { + const alive = Object.values(s.members).filter((c) => c.alive) + const dead = Object.values(s.members).filter((c) => !c.alive) + const sorted = [...alive].sort((a, b) => { + const aHead = a.id === headId ? -1 : 0 + const bHead = b.id === headId ? -1 : 0 + return aHead - bHead || world.ageOf(b) - world.ageOf(a) + }) + const marriageReady = alive.filter( (c) => world.ageOf(c) >= 16 && world.ageOf(c) <= 46 && c.state !== 'expedition' && (!c.spouseId || world.isWidowed(c)) ) - })() + return { alive, dead, sorted, marriageReady } + }, [s.members, headId, world]) + const selected = selectedMemberId ? s.members[selectedMemberId] as Character | undefined : undefined + + // 0.1.39:稳定回调引用——避免每次渲染新建函数导致 MemberCard memo 失效 + const onSelect = setSelected return (
@@ -78,10 +83,10 @@ export default function FamilyPanel() { )}
{sorted.map((c) => ( - + ))} {dead.map((c) => ( - + ))}
{alive.length === 0 && (