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

Next.js使用自定义React Hook报Objects are not valid as a React child错误

问题排查与解决方案

错误原因

报错和自定义Hook的setUsername逻辑无关,核心触发点是Enter页面的渲染分支直接调用了router.push()方法:
router.push()是Next.js提供的异步路由跳转方法,调用后会返回Promise对象,你直接将它写在JSX的条件渲染分支中,React尝试将这个Promise作为子元素渲染,就触发了「Objects are not valid as a React child (found: [object Promise])」的错误。
而setUsername执行时会触发消费UserContext的组件重渲染,刚好走到了router.push的分支,所以会被误定位为报错来源。

修复方案

1. 核心修复逻辑

不要在JSX的渲染分支中直接执行路由跳转,用useEffect监听user和username的状态变化,满足跳转条件时再触发跳转。

2. 额外优化点

  • 异步事件处理函数中返回的JSX不会被渲染,需要用state存储错误信息再渲染到视图中
  • React中DOM的class属性要写成className,for属性要写成htmlFor避免控制台警告

修改后的完整代码

import { useRouter } from "next/dist/client/router";
import { useContext, useState, useEffect } from "react";
import { UserContext } from "../lib/Context";
import { auth, googleAuthProvider, firestore} from "../lib/firebase";

export default function Enter({}) {
  const { user, username } = useContext(UserContext);
  const router = useRouter();

  // 用useEffect处理跳转逻辑,不要直接写在JSX里
  useEffect(() => {
    if (user && username) {
      router.push("/");
    }
  }, [user, username, router]);

  return (
    <>
      <div className="container my-3">
        {/* 只渲染需要展示的组件,跳转逻辑放到effect里 */}
        {!user ? <Login /> : !username ? <UserNameForm /> : null}
      </div>
    </>
  );
}

// 登录组件修改错误提示逻辑
const Login = () => {
  const [errorMsg, setErrorMsg] = useState('');
  const signinwithgoogle = async () => {
    try {
      setErrorMsg('');
      await auth.signInWithPopup(googleAuthProvider);
    } catch (error) {
      console.error(error.message);
      setErrorMsg('登录过程出现错误,请重试');
    }
  };

  return (
    <>
      <div className="d-flex justify-content-center">
        <h3>使用谷歌账号注册或登录</h3>
      </div>
      {errorMsg && <div className="d-flex justify-content-center text-danger my-2">{errorMsg}</div>}
      <div className="d-flex justify-content-center my-4">
        <button onClick={signinwithgoogle} className="btn btn-primary">
          注册 <i className="fab fa-google"></i>
        </button>
      </div>
    </>
  );
};

// 用户名提交表单
const UserNameForm = () => {
  const [formValue, setFormValue] = useState("");
  const {user} = useContext(UserContext)
  const onChange = (e) => {
    setFormValue(e.target.value);
  };
  const onSubmit = async (e) => {
    e.preventDefault();

    // 批量写入用户数据
    const userDoc = firestore.doc(`users/${user.uid}`);
    const usernameDoc = firestore.doc(`usernames/${formValue}`);
    const batch = firestore.batch();
    batch.set(userDoc, { username: formValue, photoURL: user.photoURL, displayName: user.displayName });
    batch.set(usernameDoc, { uid: user.uid });

    await batch.commit();
  };
  return (
    <>
      <form onSubmit={onSubmit}>
        <div className="mb-3">
          <label htmlFor="usernameInput" className="form-label">
            请输入用户名
          </label>
          <input
            value={formValue}
            onChange={onChange}
            type="text"
            className="form-control"
            id="usernameInput"
            minLength={4}
            required
          />
        </div>
        <button type="submit" className="btn btn-primary">
          提交
        </button>
      </form>
    </>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 22:45:03