簡體   English   中英

在 React 中 history.push() 時無法設置新組件的狀態

[英]Not able to set state of new component when history.push() in React

我正在嘗試使用 OAuth2 授權代碼授權類型為 React 前端創建登錄流。 我已經能夠將用戶定向到身份驗證服務器的登錄頁面,成功登錄后重定向到我的反應前端: "http:localhost:3000/oauth_callback?code={auth_code}"

然后呈現 LoginCallback 組件,該組件采用 auth_code 值並發送 POST fetch 請求以獲取訪問令牌,響應將如下所示:

{
access_token: "640f3dce-11c6-45fe-8984-517ecce471ae", 
token_type: "bearer", 
expires_in: 37822, 
scope: "read"
}

返回后,我嘗試使用 history.push() 將用戶導航到 Dashboard 組件,響應數據處於 Dashboards 狀態。

我遇到的問題是我無法使用獲取請求的響應來設置狀態,並且因為 LoginCallback 組件是從身份驗證服務器重定向到的,所以沒有父組件可以將狀態發送回。

登錄回調:

import React, { FC, useEffect } from "react";
import { RouteComponentProps, useHistory } from "react-router-dom";
import Dashboard from "./components/Dashboard";

const LoginCallback: FC<RouteComponentProps> = ({ location }) => {
  const history = useHistory();
  var response = {
    access_token: '',
    token_type: '',
    expires_in: 0,
    scope: ''
  }
  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(res => console.log(res))
      .then(res => JSON.stringify(res))
      .then(res => {
        console.log(`json.stringify(): ${JSON.stringify(res)}`);    // returns undefined
        console.log(`json.parse(): ${JSON.parse(res)}`);
        response = JSON.parse(res);                                 // returns syntaxError: Unexpected token u in JSON at position 0
        history.push({pathname: '/dashboard', state: {
          authenticated: true,
          access_token: response.access_token,
          token_type: response.token_type,
          expires_in: response.expires_in,
          scope: response.scope
        }});
      })
      .catch(console.error);
  }, []);
  return null;
};

export default LoginCallback;

儀表盤:

import { render } from '@testing-library/react';
import React, {useState} from 'react';

const Dashboard = () => {
    const [state, setAllValues] = useState({
        authenticated: false,
        access_token: '',
        token_type: '',
        expires_in: 0,
        scope: ''
     });
     const changeHandler = e => {
        setAllValues({...state, [e.target.name]: e.target.value})
     }

    return (
        <div>
            { state.authenticated ? <a href="/login">Login Here</a> : <a href="/logout">Logout</a> }
            <p> Dashboard </p>
            <p> Authenticated: {state.authenticated}</p>
            { state.authenticated ?
                <p> stored access token: {state.access_token} </p>
                            :
                null
            }
            
        </div>
    );
}

export default Dashboard;

在您的儀表板組件中考慮添加以下代碼

import { useLocation } from "react-router-dom";

function Dashboard() {
  const { state } = useLocation();

  return <div>{JSON.stringify(state)}</div>;
}

我相信這將使您能夠訪問您傳入的狀態。如果沒有共享您的儀表板代碼的相關部分,我們可以看看。

對於您的 fetch 調用,請嘗試:

fetch(`http://localhost:9090/oauth/token?${qParams}`, {
  // credentials: "include",
  method: 'POST',
  headers: {
    'Authorization': 'Basic Y2xpZW50MjpzZWNyZXQy'
  }
})
  .then(res => res.json())
  .then(response => {
    history.push({pathname: '/dashboard', state: {
      authenticated: true,
      access_token: response.access_token,
      token_type: response.token_type,
      expires_in: response.expires_in,
      scope: response.scope
    }});
  })
  .catch(console.error);

我發現 axios 更易於使用。

useHistory()僅適用於HOCBrowserRouter那些組件

使用此代碼導入Dashboard

 <BrowserRouter>
        <Switch>
          <Route path="/dashboard" exact component={Dashboard} />
        </Switch>
 </BrowserRouter>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM