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

Next.js14中用Redux Toolkit查数据库遇child_process模块缺失问题

问题根源

MongoDB驱动依赖Node.js核心模块child_process,但标记为'use client'的组件运行在浏览器环境,根本没有这个模块——你直接在Redux的async thunk里调用数据库操作,等于把服务端代码硬塞到客户端跑,必然报错。

解决方案

1. 把数据库操作完全隔离到服务端

把data.ts改成Server Action,加上'use server'指令,确保所有数据库逻辑只在服务端执行:

// lib/api/data.ts
'use server';
import { MongoClient } from 'mongodb';

export async function fetchProducts(filterParams: Record<string, any>) {
  const client = await MongoClient.connect(process.env.MONGODB_URI!);
  const db = client.db();
  
  // 这里写你的过滤查询逻辑
  const products = await db.collection('products')
    .find(filterParams)
    .toArray();
  
  await client.close();
  return products;
}

2. 修改Redux Thunk,让它调用Server Action

原来的thunk不要直接操作数据库,改成调用上面的Server Action(Next.js会自动处理客户端到服务端的请求):

// lib/redux/features/filterSlice.ts
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { fetchProducts } from '@/lib/api/data';

export const getProducts = createAsyncThunk(
  'filters/getProducts',
  async (filterParams: Record<string, any>) => {
    // 调用服务端的fetchProducts,而非直接操作数据库
    const data = await fetchProducts(filterParams);
    return data;
  }
);

const filterSlice = createSlice({
  name: 'filters',
  initialState: {
    products: [],
    loading: false,
    error: null as string | null,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getProducts.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(getProducts.fulfilled, (state, action) => {
        state.loading = false;
        state.products = action.payload;
      })
      .addCase(getProducts.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message || '获取产品失败';
      });
  },
});

export default filterSlice.reducer;

3. 处理Query参数传递

Next.js 14 App Router里不用getServerSideProps了,直接在Server Component里拿searchParams,再传给客户端组件:

// app/search/page.tsx(Server Component,不用加'use client')
import ProductsContent from '@/components/products-content';

export default async function SearchPage({ searchParams }: { searchParams: Record<string, string | string[] | undefined> }) {
  // 提取并整理url里的查询参数
  const filterParams = {
    keyword: searchParams.keyword?.toString() || '',
    category: searchParams.category?.toString() || '',
  };

  return <ProductsContent initialFilters={filterParams} />;
}

然后在客户端组件里用这些初始参数触发Thunk:

// components/products-content/index.tsx('use client'组件)
'use client';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getProducts } from '@/lib/redux/features/filterSlice';

export default function ProductsContent({ initialFilters }: { initialFilters: Record<string, any> }) {
  const dispatch = useDispatch();
  const { products, loading, error } = useSelector((state: any) => state.filters);

  useEffect(() => {
    // 页面加载时用初始参数请求数据
    dispatch(getProducts(initialFilters));
  }, [dispatch, initialFilters]);

  return (
    <div>
      {loading && <p>加载中...</p>}
      {error && <p className="text-red-500">{error}</p>}
      {products.map((product: any) => (
        <div key={product._id} className="border p-4 mb-2">
          <h3>{product.name}</h3>
          <p>{product.price}</p>
        </div>
      ))}
    </div>
  );
}

为什么之前的方法无效?

  • getServerSideProps是Pages Router的API,App Router里已经废弃,改用Server Component直接获取参数。
  • 你之前尝试的拆分代码没到位——只要Redux Thunk里还直接引入MongoDB驱动,它就会跟着客户端组件打包到浏览器,必然触发模块找不到的错误。必须把数据库操作完全放到服务端,客户端只负责调用服务端接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:47:33