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

React组件表单JSON数据存为文件报错求助:fs.writeFile未定义

解决React组件中表单数据保存为JSON并跨组件读取的问题

首先得给你理清为什么会报错:fs是Node.js的核心模块,只能在服务器端运行,而你的React组件是在浏览器环境里执行的,浏览器压根没有这个API,所以才会出现“fs.writeFile is not a function”的错误。下面给你几个不同场景下的可行解决方案,你可以根据自己的需求选:

方案一:前端直接生成并下载JSON文件(无需后端)

如果你的需求是让用户把表单数据下载到本地,之后可以通过另一个组件上传读取,那这个方案最适合:

表单组件:生成并下载JSON

在表单提交时,把收集到的数据转成JSON字符串,然后通过浏览器的Blob API生成下载链接:

import { useState } from 'react';

function FormComponent() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    // 把表单数据转成格式化的JSON字符串
    const jsonString = JSON.stringify(formData, null, 2);
    // 创建Blob对象
    const blob = new Blob([jsonString], { type: 'application/json' });
    // 生成下载链接
    const url = URL.createObjectURL(blob);
    // 创建临时a标签触发下载
    const downloadLink = document.createElement('a');
    downloadLink.href = url;
    downloadLink.download = 'form-submission.json'; // 设置下载文件名
    document.body.appendChild(downloadLink);
    downloadLink.click();
    // 清理资源
    document.body.removeChild(downloadLink);
    URL.revokeObjectURL(url);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="name"
        value={formData.name}
        onChange={handleInputChange}
        placeholder="姓名"
        required
      />
      <input
        type="email"
        name="email"
        value={formData.email}
        onChange={handleInputChange}
        placeholder="邮箱"
        required
      />
      <textarea
        name="message"
        value={formData.message}
        onChange={handleInputChange}
        placeholder="留言"
        required
      />
      <button type="submit">保存为JSON并下载</button>
    </form>
  );
}

export default FormComponent;

读取组件:上传并解析JSON文件

在另一个组件里做一个文件上传功能,读取用户上传的JSON文件:

import { useState } from 'react';

function DataReaderComponent() {
  const [uploadedData, setUploadedData] = useState(null);
  const [error, setError] = useState('');

  const handleFileUpload = (e) => {
    const file = e.target.files[0];
    if (!file) return;

    // 校验文件类型
    if (file.type !== 'application/json') {
      setError('请上传JSON格式的文件');
      return;
    }

    const reader = new FileReader();
    reader.onload = (event) => {
      try {
        const parsedData = JSON.parse(event.target.result);
        setUploadedData(parsedData);
        setError('');
      } catch (err) {
        setError('文件内容不是有效的JSON');
        setUploadedData(null);
      }
    };
    reader.readAsText(file);
  };

  return (
    <div>
      <input type="file" accept=".json" onChange={handleFileUpload} />
      {error && <p style={{ color: 'red' }}>{error}</p>}
      {uploadedData && (
        <div>
          <h3>读取到的表单数据:</h3>
          <pre>{JSON.stringify(uploadedData, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

export default DataReaderComponent;

方案二:用React状态管理共享数据(同项目内组件)

如果两个组件在同一个React应用里,只是需要在内存中共享数据,根本不需要生成文件,用状态管理方案更高效,比如Context API(轻量)或者Redux/Zustand(复杂场景):

1. 创建数据共享Context

import { createContext, useContext, useState } from 'react';

const FormDataContext = createContext();

export function FormDataProvider({ children }) {
  const [sharedFormData, setSharedFormData] = useState(null);

  return (
    <FormDataContext.Provider value={{ sharedFormData, setSharedFormData }}>
      {children}
    </FormDataContext.Provider>
  );
}

// 自定义Hook,方便组件调用
export function useFormData() {
  return useContext(FormDataContext);
}

2. 在根组件包裹Provider

import { FormDataProvider } from './FormDataContext';
import FormComponent from './FormComponent';
import DataReaderComponent from './DataReaderComponent';

function App() {
  return (
    <FormDataProvider>
      <div style={{ display: 'flex', gap: '2rem', padding: '2rem' }}>
        <FormComponent />
        <DataReaderComponent />
      </div>
    </FormDataProvider>
  );
}

export default App;

3. 表单组件设置数据

import { useState } from 'react';
import { useFormData } from './FormDataContext';

function FormComponent() {
  const [formData, setFormData] = useState({ name: '', email: '' });
  const { setSharedFormData } = useFormData();

  const handleSubmit = (e) => {
    e.preventDefault();
    setSharedFormData(formData);
    alert('数据已共享给其他组件');
  };

  // 输入框 onChange 逻辑省略,和之前类似
  return (
    <form onSubmit={handleSubmit}>
      {/* 表单输入框 */}
      <button type="submit">共享表单数据</button>
    </form>
  );
}

4. 读取组件获取数据

import { useFormData } from './FormDataContext';

function DataReaderComponent() {
  const { sharedFormData } = useFormData();

  return (
    <div>
      <h3>共享的表单数据:</h3>
      {sharedFormData ? (
        <pre>{JSON.stringify(sharedFormData, null, 2)}</pre>
      ) : (
        <p>暂无共享数据</p>
      )}
    </div>
  );
}

方案三:用Node.js后端接口持久化数据

如果需要把数据持久化到服务器,让不同用户或不同会话都能读取,那得写一个简单的Node.js后端接口:

1. 后端代码(Express服务器)

先安装依赖:npm install express cors

const express = require('express');
const fs = require('fs');
const path = require('path');
const cors = require('cors');

const app = express();
const PORT = 3001;

// 跨域配置
app.use(cors());
// 解析JSON请求体
app.use(express.json());

// 保存表单数据的接口
app.post('/api/save-form', (req, res) => {
  const formData = req.body;
  const filePath = path.join(__dirname, 'form-data.json');

  fs.writeFile(filePath, JSON.stringify(formData, null, 2), (err) => {
    if (err) {
      console.error('保存文件失败:', err);
      return res.status(500).json({ success: false, message: '保存失败' });
    }
    res.json({ success: true, message: '数据已保存' });
  });
});

// 获取表单数据的接口
app.get('/api/get-form', (req, res) => {
  const filePath = path.join(__dirname, 'form-data.json');

  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      console.error('读取文件失败:', err);
      return res.status(500).json({ success: false, message: '读取失败' });
    }
    try {
      const parsedData = JSON.parse(data);
      res.json({ success: true, data: parsedData });
    } catch (parseErr) {
      res.status(500).json({ success: false, message: 'JSON解析错误' });
    }
  });
});

app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

2. 前端表单组件调用保存接口

const handleSubmit = async (e) => {
  e.preventDefault();
  try {
    const response = await fetch('http://localhost:3001/api/save-form', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(formData),
    });
    const result = await response.json();
    alert(result.message);
  } catch (err) {
    console.error('请求错误:', err);
    alert('请求失败,请检查服务器是否运行');
  }
};

3. 读取组件调用获取接口

import { useEffect, useState } from 'react';

function DataReaderComponent() {
  const [formData, setFormData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('http://localhost:3001/api/get-form');
        const result = await response.json();
        if (result.success) {
          setFormData(result.data);
        }
      } catch (err) {
        console.error('请求错误:', err);
      }
    };
    fetchData();
  }, []);

  return (
    <div>
      {formData ? (
        <pre>{JSON.stringify(formData, null, 2)}</pre>
      ) : (
        <p>加载中...</p>
      )}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:01:21