Firebase 9更新指定文档时出现Uncaught TypeError错误排查
Firebase 9 更新文档时出现 TypeError: n.indexOf is not a function 问题
错误信息
Uncaught (in promise) TypeError: n.indexOf is not a function at rt.fromString (index.esm2017.js:1032:1) at sa (index.esm2017.js:16038:1) at actions.js:136:1 at Object.dispatch (index.js:16:1) at dispatch (<anonymous>:3665:80) at editFeedback (EditFeedbackPage.js:55:1) at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1) at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1) at invokeGuardedCallback (react-dom.development.js:4277:1) at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4291:1)
问题情况
- 资料显示该错误可能是引用数据库中不存在的文档导致。
- 通过
useParams()获取的文档ID,在useEffect()中能正常打印,但传入editFeedback()并在dispatch中使用时变为undefined;尝试将ID存入state后依然是undefined。 - 添加、删除、获取文档操作均正常,仅更新文档出现问题,且更新逻辑参照了正常工作的删除文档写法。
相关代码
EditFeedbackPage.js
const EditFeedbackPage = () => { const initialState = { category: "All", comments: [], detail: "", id: nanoid(), createdAt: Timestamp.now().toDate(), status: "Suggestion", title: "", upVotesCount: [] } const ref = useRef() const [state, setState] = useState(initialState); const { feedback } = useSelector((state) => state.data); const { category, detail, title, status } = feedback; console.log(feedback) const params = useParams(); const { id } = params; console.log("id from params => ", id) // id from params => TexT99K7xz1Q2a4xv5PF const dispatch = useDispatch(); const navigate = useNavigate(); const cancelAddFeedback = () => { navigate("/") } useEffect(() => { dispatch(getSingleFeedback(id)); console.log("feedbackId => ", id); }, []); const editFeedback = async (e, id) => { e.preventDefault(); console.log("feedbackId => ", id); dispatch(editFeedbackInit(id, feedback)) } const handleInputChange = (e) => { let { name, value } = e.target; setState({ ...state, [name]: value }) } const handleSubmit = (e) => { e.preventDefault(); setState({ ...state, title: '', detail: "", category: "All" }) } return ( <EditFeedbackContainer> <EditFeedbackWholeContainer> <NavbarFeedback /> <EditFeedbackInnerContainer> <h2>Edit Feedback</h2> <EditFeedbackFormContainer onSubmit={handleSubmit} > <h4>Feedback Title</h4> <label htmlFor="title">Add a short, descriptive headline</label> <input ref={ref} type="text" name='title' defaultValue={title} onChange={handleInputChange} /> --------------------- <EditFeedbackButtonsContainer> <EditFeedbackButtonDelete // onClick={deleteFeedback} > Delete </EditFeedbackButtonDelete> <EditFeedbackButtonCancel onClick={cancelAddFeedback}>Cancel</EditFeedbackButtonCancel> <EditFeedbackButtonAdd onClick={editFeedback} >Edit Feedback</EditFeedbackButtonAdd> </EditFeedbackButtonsContainer> </EditFeedbackFormContainer> </EditFeedbackInnerContainer> </EditFeedbackWholeContainer> </EditFeedbackContainer > ) }
actions.js(更新文档逻辑)
// edit feedbacks actions const editFeedbackStart = () => ({ type: types.EDIT_FEEDBACK_START, }); const editFeedbackSussess = () => ({ type: types.EDIT_FEEDBACK_SUCCESS, }); const editFeedbackFail = () => ({ type: types.EDIT_FEEDBACK_FAIL, }); export const editFeedbackInit = (feedback, id, err) => { return async function (dispatch) { dispatch(editFeedbackStart()); console.log(id) // await db.collection("feedbacks").doc(id).update(feedback); // console.log(id) // => also tried this version above const feedDoc = doc(db, "feedbacks", id); await updateDoc(feedDoc, feedback); console.log(id) dispatch(editFeedbackSussess()); if (err) { dispatch(editFeedbackFail(err)) } }; }
正常工作的删除文档逻辑
export const deleteFeedbackInit = (id, err) => { return function (dispatch) { dispatch(deleteFeedbackStart()); db.collection("feedbacks").doc(id).delete(); dispatch(deleteFeedbackSussess()); if (err) { dispatch(deleteFeedbackFail(err)) } }; }
问题根源与解决方案
两个核心错误
函数参数顺序不匹配
editFeedbackInit定义的参数顺序是(feedback, id, err),但在editFeedback中调用时传入的是(id, feedback),导致Firebase收到的id实际是feedback对象。对象没有indexOf方法,因此触发报错。
onClick未传递id参数
editFeedback函数定义了(e, id)参数,但<EditFeedbackButtonAdd onClick={editFeedback}>仅传递了事件对象e,id参数未传入,导致editFeedback中的id为undefined。
修正步骤
步骤1:修正参数传递
- 方法一:修改
editFeedback的调用方式,显式传递id
<EditFeedbackButtonAdd onClick={(e) => editFeedback(e, id)} >Edit Feedback</EditFeedbackButtonAdd>
- 方法二:去掉
editFeedback的id参数,直接使用组件内的id变量
const editFeedback = async (e) => { e.preventDefault(); console.log("feedbackId => ", id); dispatch(editFeedbackInit(id, feedback)) }
步骤2:统一参数顺序
将actions.js中的editFeedbackInit参数顺序改为(id, feedback, err),与调用顺序一致:
export const editFeedbackInit = (id, feedback, err) => { return async function (dispatch) { dispatch(editFeedbackStart()); console.log(id) const feedDoc = doc(db, "feedbacks", id); await updateDoc(feedDoc, feedback); console.log(id) dispatch(editFeedbackSussess()); if (err) { dispatch(editFeedbackFail(err)) } }; }
内容的提问来源于stack exchange,提问作者lsokol
相关产品推荐
相关产品推荐

