【问题标题】: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' />
          )} 
        />
    );
}

【问题讨论】:

    标签: reactjs react-router react-hooks


    【解决方案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 标签并使用它(而不是重复这个三元组)。

    【讨论】:

      猜你喜欢
      • 2023-01-25
      • 2023-01-17
      • 2021-08-02
      • 1970-01-01
      • 2020-12-09
      • 2020-01-12
      • 2020-06-01
      • 1970-01-01
      • 2022-08-07
      相关资源
      最近更新 更多