React with Router v5 Error: Objects are not valid as a React child (found: object with keys children

Posted

技术标签:

【中文标题】React with Router v5 Error: Objects are not valid as a React child (found: object with keys children)【英文标题】:React with Router v5 Error: Objects are not valid as a React child (found: object with keys children)React with Router v5 Error: Objects are not valid as a React child (found: object with keys children) 【发布时间】:2021-06-29 17:01:15 【问题描述】:

我是新手,但我试图创建一个本质上是 2 个应用程序合二为一的网络应用程序。将 2 个应用程序合二为一是指我有 2 个单独的布局,一个是授权的,一个是非授权的。我当前登录时遇到问题,当我尝试在成功登录时重定向时出现以下错误:

错误:对象作为 React 子对象无效(找到:带有键 children 的对象)。如果您打算渲染一组子项,请改用数组。

我确定这与我如何设置路线或我如何重定向有关。

这是我的所有代码。该错误通常指向handlesubmit 函数中login.js 中的history.push 行。注意:我的代码实际上被拆分为每个函数的多个 js 文件,我只是在这里将它们组合起来,这样代码会更紧凑一些(我还为这个示例组合了导入)。

更新:我想我将问题缩小到我的 ProtectedRoute 组件,但我仍然不完全知道问题是什么。我认为这是我如何将一组路径传递给该组件,但我不确定如何修复它。

import React,  useState,useEffect  from "react";
import  NavLink, Route, Switch, useRouteMatch, useHistory, useLocation, useParams  from 'react-router-dom';
import MainLayout from "../layouts/MainLayout";
import AuthLayout from "../layouts/AuthLayout";
import NotFound from "../pages/NotFound";
import Login from "../pages/Login";
import Welcome from "../pages/Welcome";
import Dashboard from "../pages/Dashboard";
import Locations from "../pages/Locations";
import ProtectedRoute from "./ProtectedRoute";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import  LinkContainer  from "react-router-bootstrap";
import  ReactComponent as Logo  from '../images/Logo.svg';
import  useAppContext  from "../libs/contextLib";
import  LinkContainer  from "react-router-bootstrap";
import  useAppContext  from "../libs/contextLib";
import axios from 'axios';
import Form from "react-bootstrap/Form";
import LoaderButton from "../components/LoaderButton";
import LoginImage from '../images/Login-Page-Image.png';
import FloatLabelTextBox from "../components/FloatLabelTextBox.js"
import  API_BASE_URL, ACCESS_TOKEN_NAME  from '../constants/apiConstants.js';
import  onError  from "../libs/errorLib";

export default function MainRoutes() 
    return (
        <Switch>
            <Route path=['/login', '/welcome']>
                <AuthLayout>
                    <Route path='/login' component=Login />
                    <Route path='/welcome' component=Welcome />
                </AuthLayout>
            </Route>            
            <ProtectedRoute exact path=['/', '/locations']>
                <MainLayout>                    
                    <Route path='/locations' component=Locations />
                    <Route exact path='/' component=Dashboard />
                </MainLayout>
            </ProtectedRoute>
            /* Finally, catch all unmatched routes */
            <Route>
                <NotFound />
            </Route>
        </Switch>
    );

function AuthLayout(children)     
    const  isAuthenticated  = useAppContext();
    return (
        <>
            <div className="AuthLayout container py-3">
                <Navbar collapseOnSelect expand="md" className="mb-3 login-nav">
                    <LinkContainer to="/welcome">
                        <Navbar.Brand href="/welcome" className="font-weight-bold text-muted">
                            <Logo />
                        </Navbar.Brand>
                    </LinkContainer>
                    <Navbar.Toggle />
                    <Navbar.Collapse className="justify-content-end">
                        <Nav activeKey=window.location.pathname>
                            <LinkContainer to="/welcome">
                                <Nav.Link>Home</Nav.Link>
                            </LinkContainer>
                            <LinkContainer to="/login">
                                <Nav.Link>Login</Nav.Link>
                            </LinkContainer>
                        </Nav>
                    </Navbar.Collapse>
                </Navbar>
                <div className="Auth-Layout-Body">
                    children
                </div>
            </div>
        </>
    );

export default AuthLayout;    

function MainLayout( children ) 
  const  isAuthenticated  = useAppContext();
  const  userHasAuthenticated  = useAppContext();
  const history = useHistory();
  
  function handleLogout() 
    userHasAuthenticated(false);
    console.log("log out");
    history.push("/login");
  
  return (
    <>
      <div className="MainLayout container py-3">
        <Navbar collapseOnSelect expand="md" className="mb-3 login-nav">
          <LinkContainer to="/">
            <Navbar.Brand href="/" className="font-weight-bold text-muted">
              Location INTEL
          </Navbar.Brand>
          </LinkContainer>
          <Navbar.Toggle />
          <Navbar.Collapse className="justify-content-end">
            <Nav activeKey=window.location.pathname>
              <LinkContainer to="/">
                <Nav.Link>Home</Nav.Link>
              </LinkContainer>
              <LinkContainer to="/locations">
                <Nav.Link>Locations</Nav.Link>
              </LinkContainer>
              isAuthenticated ? (
                <Nav.Link onClick=handleLogout>Logout</Nav.Link>
              ) : (<div></div>)
            </Nav>
          </Navbar.Collapse>
        </Navbar>
        <div className="Main-Layout-Body">
          children
        </div>
      </div>
    </>
  );

export default MainLayout;    

export default function Login() 
    const history = useHistory();
    const [state, setState] = useState(
        email: "",
        password: "",
    );
    const  userHasAuthenticated  = useAppContext();
    const [isLoading, setIsLoading] = useState(false);

    const handleChange = (e) => 
        setState(
            ...state,
            [e.target.name]: e.target.value,
        )
    

    function validateForm() 
        return state.email.length > 0 && state.password.length > 0;
    

    function handleSubmit(event) 
        event.preventDefault();

        setIsLoading(true);

        const payload = 
            "email": state.email,
            "password": state.password,
        
        try     
            axios.post('/api/user/login', payload, 
                headers: 
                    useCredentails: true,
                    'x-api-key': ACCESS_TOKEN_NAME,
                    "Access-Control-Allow-Origin": "*"
                
            )
                .then(function (response) 
                    console.log(response);
                    //console.log('status code = ' + response.status);
                    if (response.status === 200) 
                        console.log("logged in");
                        userHasAuthenticated(true);
                        history.push("/");
                     else 
                        console.log("not logged in");
                    
                )
                .catch(function (error) 
                    console.log(error);
                );

         catch (e) 
            onError(e);
            setIsLoading(false);
        
    

    return (
        <div className="Login-Container">
            <div className="Login-Container-Row">
                <div className="Login">
                    <p className="Login-Header">Login</p>
                    <div className="Login-Form">
                        <Form onSubmit=handleSubmit>
                            <Form.Group size="lg" controlId="email">
                                <FloatLabelTextBox
                                    inputLabel="EMAIL"
                                    inputAutoFocus="autofocus"
                                    inputType="email"
                                    inputName="email"
                                    inputPlaceholder="Email"
                                    inputValue=state.email
                                    handleChangeProps=handleChange
                                />
                            </Form.Group>
                            <Form.Group size="lg" controlId="password">
                                <FloatLabelTextBox
                                    inputLabel="PASSWORD"
                                    inputAutoFocus=""
                                    inputType="password"
                                    inputName="password"
                                    inputPlaceholder="Password"
                                    inputValue=state.password
                                    handleChangeProps=handleChange
                                />
                            </Form.Group>
                            <LoaderButton
                                block
                                size="lg"
                                type="submit"
                                isLoading=isLoading
                                disabled=!validateForm()>
                                Login
                            </LoaderButton>
                            <p>Not a member? <NavLink to="/register">Get Started Here</NavLink></p>
                        </Form>
                    </div>
                </div>
                <div className="Login-Image">
                    <img src=LoginImage />
                </div>
            </div>
        </div>
    );


export default function ProtectedRoute( children, ...props ) 
    const  isAuthenticated  = useAppContext();
    return (
        <Route 
          ...props 
          render=props => (
            isAuthenticated ?
              children :
              <Redirect to='/login' />
          ) 
        />
    );

【问题讨论】:

【参考方案1】:

你的问题在这里:

    <Route 
      ...props 
      render=props => (
        isAuthenticated ?
          children : // <=== HERE!
          <Redirect to='/login' />
      )

你使用children 就像你在“JSX-land”中一样......但你不是。您已经在 J​​SX 中的一组 中……这意味着您处于“javascript 领域”。

在“Javascript 领域”中,children 的意思是“让我成为一个具有称为 children 的单个子属性的对象”。当你尝试将该对象插入到 JSX 中时,React 不知道如何处理它,你就会得到错误。

你只需要相同的代码,减去那些花括号:

    <Route 
      ...props 
      render=props => (
        isAuthenticated ?
          children :
          <Redirect to='/login' />
      )

附:不要忘记路由标签只是标签,所以如果你经常使用这种模式,你可能想要创建一个AuthenticatedRoute 标签并使用它(而不是重复这个三元组)。

【讨论】:

以上是关于React with Router v5 Error: Objects are not valid as a React child (found: object with keys children的主要内容,如果未能解决你的问题,请参考以下文章

react-router路由之routerRender方法(v5 v6)

react-router-dom v5和react-router-dom v6区别

react-router-dom V5 使用指南

如何在 React Router v5 中推送到历史记录?

如何在 React Router v5 中推送到历史记录?

React开发中使用react-router-dom路由最新版本V5.1.2基本跳转属性