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

React中Firestore的setDoc/addDoc无法添加文档求助

React项目Firestore setDoc/addDoc无法写入文档排查

问题描述

在React项目中调用Firestore的setDoc或addDoc方法时,无法将文档添加到指定集合,控制台无任何报错输出。已通过登录验证确认Firebase连接正常,传入参数也无问题,求可能原因。

相关代码

FirebaseFile.js

import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

var firebaseConfig = {
  ...
};

// Initialize Firebase
var app = initializeApp(firebaseConfig);
export const db = getFirestore(app);

Another.js

import React, { useRef, useState } from 'react';
import { doc, setDoc,collection } from 'firebase/firestore';

import styled from 'styled-components';
import EmailEditor from '../../../src';
import sample from './sample.json';
import sample2 from './sample2.json';
import sample3 from './sample3.json';
import { db } from '../firebase';
import Checkbox from '@mui/material/Checkbox';
import axios from 'axios';
const label = { inputProps: { 'aria-label': 'Checkbox demo' } };

const Container = styled.div`
  display: flex;
  flex-direction: column;
  position: relative;
  height: 100%;
`;

const Bar = styled.div`
  flex: 1;
  background-color: #000000;
  color: #000;
  padding: 10px;
  display: flex;
  max-height: 40px;

  h1 {
    flex: 1;
    font-size: 16px;
    text-align: left;
  }

  button {
    flex: 1;
    padding: 10px;
    margin-left: 10px;
    font-size: 14px;
    font-weight: bold;
    background-color: #000;
    color: #fff;
    border: 0px;
    max-width: 150px;
    cursor: pointer;
  }
`;

const Example = () => {
  const emailEditorRef = useRef(null);
  const [titolo, setTitolo] = useState('');
  const [newsProfileValue, setNewsProfileSet] = useState('');
  const [profileList, setNewsProfileList] = useState([]);
  const [premiumValue, setPremium] = useState(false);
  const [publicValue, setPublic] = useState(false);
  const arr = [];

  const saveDesign = () => {
    emailEditorRef.current.editor.saveDesign((design) => {
      exportData(design);
    });
  };

  const getList = async () => {
    try {
      //Recupero lo user id
      var id = await localStorage.getItem('uid');
      console.log(id);
      var data = [];
      const querySnapshot = await getDocs(collection(db, 'news_profiles'));
      querySnapshot.forEach((doc) => {
        if (doc.data().about.uid == id) {
          data.push({ title: doc.data().about.title, id: doc.id });
          arr.push({ doc: doc.data().about.title, id: doc.id });
        }
      });
    } catch (error) {
      console.log('Error: ' + error);
    }
    var options = arr.map((e) => {
      return `<option value="${e.id}">${e.doc}</option>`;
    });
    document.getElementById('selectNumber').innerHTML = options;
    setNewsProfileList(data);
  };

  const exportData = (design) => {
    const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
      JSON.stringify(design)
    )}`;
    const link = document.createElement('a');
    link.href = jsonString;
    link.download = 'data.json';
    link.click();
  };
  const exportHtml = () => {
    console.log('Sono in export html');
    addElementToFireStoreNews('prova');
    emailEditorRef.current.editor.exportHtml((data) => {
      const { design, html } = data;
      console.log('Sono dentor export');
      addElementToFireStoreNews(html);
      console.log("Sono dentor l'export");
    });
  };

  const addElementToFireStoreNewsAWS = async (html) => {
    var jsonFile;
    var templateid = await localStorage.getItem('templateid');
    if (templateid == 1) {
      jsonFile = sample;
    } else if (templateid == 2) {
      jsonFile = sample3;
    } else {
      jsonFile = sample2;
    }
    //Salvo la newsletter su aws
    emailEditorRef.current.editor.exportHtml((data) => {
      const { design, html } = data;
      var dataValue = {
        internal: true,
        online: publicValue,
        premium: premiumValue,
        html: html,
        template: jsonFile,
        subject: html,
        email: uuid,
      };
      axios
        .post(
          `https://europe-west3-mindit-newsletter.cloudfunctions.net/newsCreate`,
          dataValue
        )
        .then((res) => {
          console.log(res.json());
        });
    });
  };
  const addElementToFireStoreNews = async (html) => {
    console.log("Sono nell'inserimento del html");
    try {
      //addElementToFireStoreNewsAWS(html);
      var uuid = await localStorage.getItem('uid');
      const value = {
        aboutNews: {
          email: newsProfileValue,
          html: html,
          internal: true,
          photo: '',
          title: titolo,
        },
        date: new Date(),
        id: uuid,
        measures: {
          impression: {
            total: 0,
          },
          views: {
            moth: 0,
            total: 0,
            week: 0,
          },
        },
        public: true,
        searchKey: '',
        premium: premiumValue,
      };

      const newCityRef = doc(collection(db, 'news'));
      await setDoc(newCityRef, value);
    } catch (err) {
      console.log('Errore inserimnento: ' + err);
    }
  };

  const onDesignLoad = (data) => {
    console.log('onDesignLoad', data);
  };

  const onLoad = async () => {
    getList();

    var templateid = await localStorage.getItem('templateid');
    if (templateid == 1) {
      emailEditorRef.current.editor.loadDesign(sample);
    } else if (templateid == 2) {
      emailEditorRef.current.editor.loadDesign(sample3);
    } else {
      emailEditorRef.current.editor.loadDesign(sample2);
    }
    emailEditorRef.current.editor.addEventListener(
      'design:loaded',
      onDesignLoad
    );
  };

  const onReady = () => {};

  const changeText = (text) => {
    setTitolo(text);
  };

  const clickValue = (e) => {
    setNewsProfileSet(e.target.value);
  };

  const changeValue = () => {
    setPremium(!premium);
  };
  const changeValuePublic = () => {
    setPublic(!publicValue);
  };

  return (
    <Container>
      <Bar>
        <img src="firebase.png" width="100" height="50" />
        <label style={{ color: 'white' }}>
          <b>Titolo News: </b>
          <input
            type="text"
            name="name"
            onChange={(value) => changeText(value.target.value)}
            style={{ marginRight: 200 }}
          />
          Premium:{' '}
          <Checkbox
            {...label}
            unchecked
            onClick={() => changeValue()}
            style={{ color: 'white' }}
          />
          Online:{' '}
          <Checkbox
            {...label}
            unchecked
            onClick={() => changeValuePublic()}
            style={{ color: 'white' }}
          />
        </label>
        <form id="myForm">
          <select id="selectNumber" onClick={clickValue}>
            <option>Scegli il news profile</option>
          </select>
          <button onClick={() => saveDesign}> Salva Design </button>
          <button onClick={() => addElementToFireStoreNews('prova')}>
            {' '}
            Salva Articolo{' '}
          </button>{' '}
        </form>
      </Bar>
      <React.StrictMode>
        <EmailEditor ref={emailEditorRef} onLoad={onLoad} onReady={onReady} />{' '}
      </React.StrictMode>{' '}
    </Container>
  );
};

export default Example;

可能的原因及排查方案

1. Firestore安全规则限制

这是最常见的原因,默认的Firestore安全规则会拒绝未授权的写入操作。检查Firebase控制台中Firestore的安全规则,确认是否允许当前用户写入news集合。

  • 临时测试可将规则设置为开放(仅测试用,上线前务必改回):
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
  • 正式环境应基于用户身份验证设置规则,比如:
allow write: if request.auth != null;

2. 表单提交默认行为未阻止

你在<form>标签内放置了操作按钮,点击时会触发表单默认提交行为,导致页面刷新,异步的setDoc操作可能还未完成就被中断。

  • 解决方法:修改按钮点击事件,阻止默认行为:
<button onClick={(e) => {
  e.preventDefault();
  addElementToFireStoreNews('prova');
}}> Salva Articolo </button>

或者将按钮类型设置为button,避免触发表单提交:

<button type="button" onClick={() => addElementToFireStoreNews('prova')}> Salva Articolo </button>

3. 关键变量值异常

检查localStorage.getItem('uid')是否返回预期值,如果uuid为null或undefined,若安全规则依赖id字段匹配用户ID,写入操作会被静默拒绝;另外确认titolo、newsProfileValue等字段是否有符合预期的内容。

4. Date类型序列化问题

Firestore支持JavaScript的Date类型,但某些场景下可能出现序列化异常。可尝试将date字段转换为Firestore时间戳:

import { serverTimestamp } from 'firebase/firestore';
// ...
date: serverTimestamp(),

或者转换为ISO字符串:

date: new Date().toISOString(),

5. 依赖版本不兼容

确保firebase和@firebase/firestore依赖版本一致,版本不兼容可能导致静默错误。可尝试更新到最新稳定版本:

npm install firebase@latest

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 07:15:34