You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Hook结合localStorage存储next/image组件失败求助

解决方案:存储图片元数据而非React元素

问题根源

localStorage仅支持存储JSON可序列化的数据(字符串、数字、普通对象/数组),你当前尝试存储的<Image>是React元素对象,包含$$typeof: Symbol(react.element)这类无法被JSON序列化的特殊字段,因此存入后无法正常读取还原。

具体修改步骤

1. 调整Votepage组件:存储图片元数据而非React元素

将状态从存储React元素改为存储选中的voteIcon元数据(普通可序列化对象):

// Votepage组件
import { useRouter } from "next/router";
import styled from "styled-components";
import { useState } from "react";
import { StyledBackLink } from "@/components/styles/BackLink";
import VoteDetails from "@/components/VoteDetails";
import { voteIcons } from "@/Icons/dataIcons/";
import Image from "next/image";

function Votepage({ entryData, onHandleUpdateVoteEvent }) {
    // 改为存储选中的voteIcon对象,而非React元素
    const [selectedVoteIcon, setSelectedVoteIcon] = useState(null);
    const router = useRouter();
    const { id } = router.query;
    const currentEvent = entryData.find((entryToVote) => entryToVote.id === id);

    function handleVoteResult() {
        const resultVoteEvent = {
            ...currentEvent,
            // 存储元数据对象
            voteResult: selectedVoteIcon,
        };
        onHandleUpdateVoteEvent(resultVoteEvent);
    }

    return (
        <>
            <StyledMain>
                <StyledBackLink href="/">Home</StyledBackLink>

                <StyledVoteTitle>Voting</StyledVoteTitle>
                <StyledVoteEventCard>
                    <VoteDetails
                        // 传递元数据,在VoteDetails内部渲染Image
                        selectedVoteIcon={selectedVoteIcon}
                        currentEvent={currentEvent}
                    />

                    <StyledEmojiCheckmark>
                        {/* 用元数据渲染Image组件 */}
                        {selectedVoteIcon && (
                            <Image
                                width={50}
                                height={50}
                                src={selectedVoteIcon.imageSrc}
                                alt={selectedVoteIcon.description}
                            />
                        )}
                    </StyledEmojiCheckmark>
                </StyledVoteEventCard>

                <StyledVoteButtonContainer>
                    {voteIcons.map((voteIcon) => (
                        <StyledVoteButtons
                            key={voteIcon.id}
                            // 点击时存储voteIcon元数据
                            onClick={() => setSelectedVoteIcon(voteIcon)}
                        >
                            <Image
                                width={80}
                                height={80}
                                src={voteIcon.imageSrc}
                                alt={voteIcon.description}
                            />
                        </StyledVoteButtons>
                    ))}
                </StyledVoteButtonContainer>

                <StyledButtonConfirm type="button" onClick={handleVoteResult}>
                    Confirm
                </StyledButtonConfirm>
            </StyledMain>
        </>
    );
}

2. 调整VoteDetails组件(适配元数据)

如果VoteDetails之前直接接收voteCheckmarkImage渲染,现在需要改为接收selectedVoteIcon并内部生成Image:

// VoteDetails组件示例
import Image from "next/image";

function VoteDetails({ selectedVoteIcon, currentEvent }) {
    return (
        <div>
            {/* 原有组件内容 */}
            {selectedVoteIcon && (
                <Image
                    width={50}
                    height={50}
                    src={selectedVoteIcon.imageSrc}
                    alt={selectedVoteIcon.description}
                />
            )}
        </div>
    );
}

3. 验证存储逻辑

现在voteResult存储的是普通对象(包含imageSrc、description、id等字段),可被Immer和localStorage正常序列化与存储。当从localStorage读取entryData后,只需用存储的元数据重新渲染<Image>即可。

补充优化建议

  • 若想进一步减少存储体积,可仅存储voteIcon.id,之后通过voteIcons.find(icon => icon.id === storedId)找回完整元数据。
  • 所有存入localStorage的数据,必须是JSON.stringify可处理的类型,避免存储函数、Symbol、React元素、类实例等复杂对象。

内容的提问来源于stack exchange,提问作者hossi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:35:42