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

Next.js 14 app router中MobX store的TypeScript类型定义问题

解决TypeScript错误与MobX Store类型定义优化

一、直接修复当前代码的类型错误

1. 补充缺失的接口定义

你代码中使用了ICard但未声明,先补上类型定义:

interface ICard {
  text: string;
  answer: string;
  isRevealed: boolean;
}

2. 给Home组件的Props指定类型

TypeScript报错是因为组件props默认被推断为{},需要明确props的类型结构:

// 定义Home组件的Props类型
interface HomeProps {
  store: ObservableClickStore;
}

// 给组件绑定Props类型
const Home = observer(({ store }: HomeProps) => {
  // ... 原组件逻辑
});

添加上述代码后,"Property 'store' does not exist on type '{}'"的错误即可解决。

二、优化代码结构(解决冗余传递问题)

你当前将Store与组件写在同一文件,且手动层层传递store的方式确实冗余,可按以下方式优化:

1. 抽离MobX Store到单独文件

创建src/stores/clickStore.ts,将Store逻辑单独封装:

import { makeObservable, observable, action, autorun } from "mobx";

export interface ICard {
  text: string;
  answer: string;
  isRevealed: boolean;
}

export class ObservableClickStore {
  counter: number = 0;
  openedCards: ICard[] = [];
  clickedCards: ICard[] = [];
  nonShuffledCharacters: ICard[] = [
    { text: "Saya", answer: "I", isRevealed: false },
    // 其他卡片数据...
  ];

  characters = this.nonShuffledCharacters.sort(() => Math.random() - 0.5);

  constructor() {
    makeObservable(this, {
      counter: observable,
      characters: observable,
      clickCard: action,
      toggleIsRevealed: action,
      clearClickedCards: action,
      reset: action,
    });
    autorun(() => console.log(this.report));
  }

  get report() {
    return this.characters;
  }

  toggleIsRevealed = (card: ICard) => {
    const index = this.characters.indexOf(card);
    if (index !== -1) {
      this.characters[index].isRevealed = !this.characters[index].isRevealed;
    }
  };

  clearClickedCards = () => {
    this.clickedCards = [];
  };

  reset = () => {
    // 重置逻辑...
  };

  clickCard = (card: ICard) => {
    // 点击逻辑...
  };
}

// 创建Store实例
export const observableClickStore = new ObservableClickStore();

2. 使用React Context传递Store

创建src/stores/StoreContext.tsx,通过上下文避免手动传递store:

import { createContext, useContext } from "react";
import { ObservableClickStore } from "./clickStore";

// 创建上下文
const StoreContext = createContext<ObservableClickStore | undefined>(undefined);

// 上下文Provider组件
export const StoreProvider = ({ children }: { children: React.ReactNode }) => {
  return (
    <StoreContext.Provider value={observableClickStore}>
      {children}
    </StoreContext.Provider>
  );
};

// 自定义Hook,简化Store获取
export const useStore = () => {
  const store = useContext(StoreContext);
  if (!store) {
    throw new Error("useStore必须在StoreProvider范围内使用");
  }
  return store;
};

3. 在Next.js根布局中配置Provider

修改src/app/layout.tsx,让所有子组件都能访问Store:

import { StoreProvider } from "@/stores/StoreContext";
// 其他导入...

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <StoreProvider>{children}</StoreProvider>
      </body>
    </html>
  );
}

4. 重构组件,通过Hook获取Store

修改src/app/page.tsx,无需手动传递store:

import { observer } from "mobx-react-lite";
import { useStore } from "@/stores/StoreContext";
// 导入QuizCard组件...

const Home = observer(() => {
  const store = useStore();
  const backside = "🍊";

  const quizCardList = store.characters.map((character, i) => (
    <div className="m-1" key={i}>
      <div onClick={() => store.clickCard(character)}>
        <QuizCard
          revealCard={character.isRevealed}
          backside={backside}
          frontside={character.text}
        />
      </div>
    </div>
  ));

  return (
    <>
      {/* 原渲染内容 */}
    </>
  );
});

const Games = () => {
  return <Home />;
};

export default Games;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:15:13