我正在尝试使用 Firebase 在后端添加一个集合中的文档,该文档的名称是随机生成的,这要归功于函数 firestoreAutoId()
但是当我提交表单时,React 返回一个错误,提示“创建时出错用户 FirebaseError:使用无效数据调用函数 DocumentReference.set()。不支持的字段值:未定义(在文档 av_deliveries/[object Object] 中的字段姓氏中找到)”
”,这可能看起来很傻,但我真的不明白为什么会出现这个错误。更改名称或值都没有关系,它会导致另一个问题。
为了更好的理解,这里是完整的代码:
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);
}
}
};
感谢您的帮助!
答案 0 :(得分: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
这一行错误地设置了对 av_deliveries/[object Object]
的引用:
firestore.doc(`av_deliveries/${id1}`); // id1 is an object of shape { id: string }
createDelivery()
当您调用 createDelivery()
时,第九个参数是用 { to_name: string }
调用的,但您期望的是 { lastname: string }
。
以下行将始终将 lastname
设置为 undefined
。
const { lastname } = { to_name: 'any string' };
解构模式的目的是将变量放入单个对象中,然后提取您需要的属性。它还旨在避免为函数提供大量参数。
这一行:
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 ... */
}
firestoreAutoId()
这些行做同样的事情(除非 firestoreAutoId()
做了一些意想不到的事情):
const id = firestoreAutoId();
/* ... */
const userRef = firebase.firestore().doc(`av_deliveries/${id}`);
const userRef = firebase.firestore().collection("av_deliveries").doc();
在您当前的代码中,您使用生成的 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
}
};