【问题标题】:React/Firebase -> DocumentReference.set() called with invalid data. Unsupported field value: undefined使用无效数据调用 React/Firebase -> DocumentReference.set()。不支持的字段值:未定义
【发布时间】:2021-03-27 19:47:28
【问题描述】:

我正在尝试使用 Firebase 在后端添加一个集合中的文档,该文档的名称是由于函数 firestoreAutoId() 而随机生成的,但是当我提交表单时,React 返回一个错误,提示“创建用户时出错 FirebaseError :使用无效数据调用函数 DocumentReference.set()。不受支持的字段值:未定义(在文档 av_deliveries/[object Object] 的字段 lastname 中找到)“ ",这可能看起来很傻,但我真的不明白为什么会出现这个错误。我改变名称或值都没有关系,它会导致另一个问题。

为了更好的理解,这里是整个代码:

AddDelivery.Js

import { createDelivery, firestoreAutoId } from '../firebase';
import './AddDelivery.css';

class AddDelivery extends Component {
    state = {when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city:''};
    handleChange = (e) => {
        const { name, value } = e.target;

        this.setState({ [name]: value });
    };
    handleSubmit = async (e) => {
        e.preventDefault();
        const {when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city} = this.state;
        try {
            let id
            id = firestoreAutoId()
            await createDelivery({ id }, { when }, { whath }, { from }, { to }, { to_adress }, { to_tel } , { name } , { to_name }, { name2 }, { tel } , { adress } ,  { info_comp } , { taken } , { taken_by } , { city });
        } catch (error) {
            console.log('error', error);
        }
        this.setState({id: '', when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city:''});
    };
    render() {
    const {when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city} = this.state;
    return (
        <div className="main-wrapper">
            <div className="form-main-wrapper">
                <p className="form-add-delivery-hero-title">Ajouter une livraison</p>
                <form className="form-wrapper" onSubmit={this.handleSubmit}>
                    <div className="form-when-wrapper">
                        <div className="form-when">
                            <label>Quand ?</label>
                            <input type="date" name="when" value={when} onChange={this.handleChange} required></input>
                        </div>
                        <div className="form-when-hour">
                            <label>A quelle heure ?</label>
                            <input type="time" name="whath" value={whath} onChange={this.handleChange} required></input>
                        </div>
                        <div className="form-city-name">
                            <label>Ville ?</label>
                            <select className="form-city-selector" name="city" value={city} onChange={this.handleChange}>
                                <option value="Lyon">Lyon</option>
                                <option value="Montpellier">Montreuil</option>
                                <option value="Paris">Paris</option>
                                <option value="Vélizy-Villacoublay">Vélizy-Villacoublay</option>
                                <option value="Viroflay">Viroflay</option>
                            </select>
                        </div>
                    </div>
                    .... Same for the rest of the form..

Firebase.js

export const createDelivery = async (id1, when1, whath1, from1, to1, adress_to1, tel_to1, name1, name2, tel1, adress1, info_comp1, taken1, taken_by1, city1) => {

  const userRef = firestore.doc(`av_deliveries/${id1}`);
  const snapshot = await userRef.get();

  if (!snapshot.exists) {
    const { id } = id1;
    const { when } = when1;
    const { whath } = whath1;
    const { from } = from1;
    const { to } = to1;
    const { adress_to } = adress_to1;
    const { tel_to } = tel_to1;
    const { name } = name1;
    const { lastname } = name2;
    const { tel } = tel1;
    const { adress } = adress1;
    const { info_comp } = info_comp1;
    const { taken } = taken1;
    const { taken_by } = taken_by1;
    const { city } = city1;

    try {
        await userRef.set({
        id,
        when,
        whath,
        from,
        to,
        adress_to,
        tel_to,
        name,
        lastname,
        tel,
        adress,
        info_comp,
        city,
      });
    } catch (error) {
      console.log('Error in creating user', error);
    }
  }
};

感谢您的帮助!

【问题讨论】:

    标签: javascript reactjs firebase google-cloud-firestore


    【解决方案1】:

    错误

    1。重置组件的状态

    您最初将您的状态设置为:

    state = {when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city:''};
    

    但这与您在创建交付后设置的状态不匹配:

    this.setState({id: '', when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city:''});
    

    你应该将你的默认状态存储为一个对象,然后用它来重置你的组件:

    const DEFAULT_STATE = {when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city:''};
    /* ... */
    state = { ...DEFAULT_STATE }; // take a shallow copy of DEFAULT_STATE
    /* ... */
    this.setState({ ...DEFAULT_STATE }); // use a shallow copy of DEFAULT_STATE
    

    2。文档 ID

    这行错误地设置了对av_deliveries/[object Object]的引用:

    firestore.doc(`av_deliveries/${id1}`); // id1 is an object of shape { id: string }
    

    3。 createDelivery() 的参数不正确

    当你调用createDelivery()时,第九个参数被调用{ to_name: string },但你期待{ lastname: string }

    以下行将始终将lastname 设置为undefined

    const { lastname } = { to_name: 'any string' };
    

    4。解构模式的错误使用

    解构模式的目的是将变量放入单个对象中,然后提取您需要的属性。它还用于避免向函数提供大量参数。

    这一行:

    await createDelivery({ id }, { when }, { whath }, { from }, { to }, { to_adress }, { to_tel } , { name } , { to_name }, { name2 }, { tel } , { adress } ,  { info_comp } , { taken } , { taken_by } , { city });
    

    应该是:

    await createDelivery({ id, when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city });
    

    或者,如果名称匹配,您可以使用其中任何一个:

    await createDelivery(this.state);
    // or
    await createDelivery({ ...this.state });
    

    这些行:

    export const createDelivery = async (id1, when1, whath1, from1, to1, adress_to1, tel_to1, name1, name2, tel1, adress1, info_comp1, taken1, taken_by1, city1) => {
      /* ... */
    
      const { id } = id1;
      const { when } = when1;
      const { whath } = whath1;
      const { from } = from1;
      const { to } = to1;
      const { adress_to } = adress_to1;
      const { tel_to } = tel_to1;
      const { name } = name1;
      const { lastname } = name2;
      const { tel } = tel1;
      const { adress } = adress1;
      const { info_comp } = info_comp1;
      const { taken } = taken1;
      const { taken_by } = taken_by1;
      const { city } = city1;
    
      /* ... */
    }
    

    应该是:

    export const createDelivery = async ({ id, when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city }) => {
      /* ... each property in the above object is available as a variable ... */
    }
    

    5。不需要firestoreAutoId()

    这些行做同样的事情(除非firestoreAutoId() 做了一些意想不到的事情):

    const id = firestoreAutoId();
    /* ... */
    const userRef = firebase.firestore().doc(`av_deliveries/${id}`);
    
    const userRef = firebase.firestore().collection("av_deliveries").doc();
    

    6。几乎不需要检查是否存在新的 auto-id 文档

    在您当前的代码中,您使用生成的 ID 创建一个新的文档引用,从数据库中读取它,然后仅在数据不存在时才写入它。

    生成的 ID 大约有 62^20 different combinations,为了有 1% 的碰撞几率,您必须生成大约 163 万亿个 ID。 Firestore 的写入限制为每秒 10k 次写入,这是多么不可能的事情,按照这个速度,您必须花费大约 517000 年的时间来达到这个上限才能获得这么多的 ID。

    所以,这些行可以删除:

    const snapshot = await userRef.get();
    if (!snapshot.exists) { /* ... */ }
    

    如果您绝对不想发生冲突,请在您的 security rules 中阻止它,而不是依赖客户端。

    应用更改

    // AddDelivery.js
    import { createDelivery } from '../firebase';
    import './AddDelivery.css';
    
    const DEFAULT_STATE = {when: '', whath: '', from: 0, to: 0, to_adress: '', to_tel: 0, name: '', to_name: '', name2: '', tel: 0, adress: '', info_comp: '', taken: false, taken_by: "X", city: ''};
    
    class AddDelivery extends Component {
      state = { ...DEFAULT_STATE };
      
      handleChange = (e) => {
        const { name, value } = e.target;
    
        this.setState({ [name]: value });
      };
      
      handleSubmit = async (e) => {
        e.preventDefault();
        try {
          await createDelivery(this.state);
        } catch (error) {
          // never called unless you have a syntax error?
          console.log('error', error);
        }
        this.setState({ ...DEFAULT_DATA });
      };
      
      render() {
        const {when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city} = this.state;
        
        /* ... */
      }
    }
    
    // firebase.js
    export const createDelivery = async ({ when, whath, from, to, to_adress, to_tel, name, to_name, name2, tel, adress, info_comp, taken, taken_by, city }) => {
      // create a new document in the "av_deliveries" collection.
      const userRef = firestore.collection("av_deliveries").doc();
      
      // to_name, taken and taken_by are unused?
      const data = {
        id: userRef.id,
        when,
        whath,
        from,
        to,
        adress_to: to_adress, // consider naming these the same
        tel_to: to_tel, // consider naming these the same
        name,
        lastname: name2, // consider naming these the same
        tel,
        adress,
        info_comp,
        city,
      };
    
      try {
        await userRef.set(data);
        return data; // return data when successful
      } catch (error) {
        console.log('Error in creating user', error);
        return false; // return false on failure
      }
    };
    

    【讨论】:

    • 确实数组有问题,变量的名字很不明确,抱歉,但是当我尝试在数据库Error in adding delivery FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field id in document av_deliveries/wcuJS9gDJXaEPmmVrWrC)的字段id中传递我的id时显示错误否则没有 id 它可以完美地工作,所以谢谢!
    • @tomdebout 通过更多错误和建议扩展了答案
    猜你喜欢
    • 2019-03-08
    • 2020-06-13
    • 2019-12-20
    • 2019-12-07
    • 2019-04-25
    • 2020-03-21
    • 2020-04-24
    • 2018-08-11
    • 2021-08-20
    相关资源
    最近更新 更多