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
相关产品推荐
相关产品推荐

