Reactjs 启动时未定义useLocation钩子:TypeError:无法读取属性';地点';未定义的

Reactjs 启动时未定义useLocation钩子:TypeError:无法读取属性';地点';未定义的,reactjs,typescript,react-router,react-hooks,Reactjs,Typescript,React Router,React Hooks,我正在编写一个typescript React应用程序,它将让用户登录并更新仪表板组件,以显示用户信息,例如他们的访问令牌和名称。我正在使用useLocation钩子在LoginCallback组件中传递获取请求的状态,以在仪表板组件中显示它 我遇到的问题是,启动时仪表板组件不会呈现,因为状态未定义,因为它尚未通过LoginCallback组件传递,这给了我一个TypeError:无法读取未定义的属性“location” 我想知道是否有办法为状态指定默认值。已验证的值,如有任何帮助,将不胜感激!

我正在编写一个typescript React应用程序,它将让用户登录并更新
仪表板
组件,以显示用户信息,例如他们的访问令牌和名称。我正在使用
useLocation
钩子在
LoginCallback
组件中传递获取请求的状态,以在仪表板组件中显示它

我遇到的问题是,启动时仪表板组件不会呈现,因为状态未定义,因为它尚未通过
LoginCallback
组件传递,这给了我一个
TypeError:无法读取未定义的属性“location”

我想知道是否有办法为
状态指定默认值。已验证的
值,如有任何帮助,将不胜感激!组件的代码如下所示:

Index.tsx:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.css';

ReactDOM.render(
  <React.StrictMode>
      <App />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();
从“React”导入React;
从“react dom”导入react dom;
导入“./index.css”;
从“./App”导入应用程序;
从“/reportWebVitals”导入reportWebVitals;
导入'bootstrap/dist/css/bootstrap.css';
ReactDOM.render(
}
{window.location.href='http://localhost:9090/oauth/authorize?response_type=code&client_id=client2&scope=read“;返回null;}}/>
);
}
导出默认应用程序;
Dashboard.js:

import React from 'react';
import {useLocation} from 'react-router-dom';

const Dashboard = () => {
    const {state} = useLocation();
    // COULD USE REDUX TO STORE USER INFO ACROSS COMPONENTS
    return (
        <div>
            <p> Dashboard </p>
            { state.authenticated ?
                <div>
                    <p>Authenticated</p>
                    <p> stored access token: {state.access_token} </p>
                    <p> refresh token: {state.refresh_token}</p>
                    <p> user: {state.user.user_name}</p>
                </div>
                            :
                <p>Not Authenticated</p>
            }
        </div>
    );
}

export default Dashboard;
从“React”导入React;
从'react router dom'导入{useLocation};
常量仪表板=()=>{
const{state}=useLocation();
//可以使用REDUX跨组件存储用户信息
返回(
仪表板

{state.authenticated? 认证

存储的访问令牌:{state.access_token}

刷新令牌:{state.refresh_-token}

用户:{state.user.user\u name}

: 未经认证

} ); } 导出默认仪表板;
LoginCallback.tsx:

import React, { FC, useEffect } from "react";
import { RouteComponentProps, useHistory } from "react-router-dom";
import jwt_decode from "jwt-decode";

const LoginCallback: FC<RouteComponentProps> = ({ location }) => {
  const history = useHistory();

  useEffect(() => {
    const code = (location.search.match(/code=([^&]+)/) || [])[1];
    const qParams = [
      `grant_type=authorization_code`,
      `scope=read`,
      `code=${code}`
    ].join("&");
    fetch(`http://localhost:9090/oauth/token?${qParams}`, {
    // credentials: "include",
    method: 'POST',
    headers: {
      'Authorization': 'Basic Y2xpZW50MjpzZWNyZXQy'
    }})
    .then(res => res.json())
    .then(response => {
      var decode = jwt_decode(response.access_token);
      history.push({pathname: '/', state: {
        authenticated: true,
        user: decode,
        access_token: response.access_token,
        token_type: response.token_type,
        refresh_token: response.refresh_token,
        expires_in: response.expires_in,
        scope: response.scope
      }});
      console.log(response);
    })
    .catch(console.error);
  }, []);
  return null;
};

export default LoginCallback;
import React,{FC,useffect}来自“React”;
从“react router dom”导入{RouteComponentProps,useHistory};
从“jwt解码”导入jwt_解码;
const LoginCallback:FC=({location})=>{
const history=useHistory();
useffect(()=>{
常量代码=(location.search.match(/code=([^&]+)/)| |[])[1];
常数qParams=[
`授权类型=授权代码`,
`范围=读取`,
`代码=${code}`
].加入(“&”);
取回(`http://localhost:9090/oauth/token?${qParams}`{
//证书:“包括”,
方法:“POST”,
标题:{
“授权”:“基本Y2xpZW50MjpzZWNyZXQy”
}})
.then(res=>res.json())
。然后(响应=>{
var decode=jwt_decode(response.access_令牌);
history.push({pathname:'/',状态:{
对,,
用户:解码,
访问令牌:response.access\u令牌,
令牌类型:response.token类型,
刷新\u令牌:response.refresh\u令牌,
expires\u in:response.expires\u in,
范围:response.scope
}});
控制台日志(响应);
})
.catch(控制台错误);
}, []);
返回null;
};
导出默认LoginCallback;

这是因为您在
包装器之外使用了
组件

useLocation
钩子需要在
组件的子组件中调用

已编辑


const Dashboard = () => {
  const { state } = useLocation();
  // COULD USE REDUX TO STORE USER INFO ACROSS COMPONENTS
  return (
    <div>
      <p> Dashboard </p>
      { state && state.authenticated ? (
        <div>
          <p>Authenticated</p>
          <p> stored access token: {state.access_token} </p>
          <p> refresh token: {state.refresh_token}</p>
          <p> user: {state.user.user_name}</p>
        </div>
      ) : (
        <p>Not Authenticated</p>
      )}
    </div>
  );
};

常量仪表板=()=>{
const{state}=useLocation();
//可以使用REDUX跨组件存储用户信息
返回(
仪表板

{state&&state.authenticated( 认证

存储的访问令牌:{state.access_token}

刷新令牌:{state.refresh_-token}

用户:{state.user.user\u name}

) : ( 未经认证

)} ); };
Hi Taghi,谢谢您的回复!我将仪表板组件移动到路由器包装器中,但仍然得到
TypeError:无法读取未定义的属性“authenticated”
这是另一个问题。您需要检查是否正在将状态传递到
位置
,或者是否是true,当用户登录时,我正在从LoginCallback组件传递状态,但启动时尚未传递,所以我需要传入一个初始值或设置一个默认值或其他什么,但我不确定如何做,只需添加另一个检查
state
,就像我上面提到的那样。如果答案对你有帮助的话,试着接受这个答案,那就行了!非常感谢你我真的很感激

const Dashboard = () => {
  const { state } = useLocation();
  // COULD USE REDUX TO STORE USER INFO ACROSS COMPONENTS
  return (
    <div>
      <p> Dashboard </p>
      { state && state.authenticated ? (
        <div>
          <p>Authenticated</p>
          <p> stored access token: {state.access_token} </p>
          <p> refresh token: {state.refresh_token}</p>
          <p> user: {state.user.user_name}</p>
        </div>
      ) : (
        <p>Not Authenticated</p>
      )}
    </div>
  );
};