开发者问题收集

无法读取数据 null 反应的属性

2021-03-04
282

我的 api 出了点问题,每次我登录并进入 Dashboard 页面 时,它都会返回 TypeError: Cannot read property 'data' of null 。 这是一个使用 JWT 身份验证登录的简单应用程序,这意味着我需要在登录时将令牌设置在语言环境存储中,我已经这样做了。但是令牌会在 15 分钟后过期,需要刷新令牌。以下是 api 的详细信息:

Retrieve the necessary data for the dashboard at 'https://freddy.codesubmit.io/dashboard'. 
This endpoint requires a 'Authorization: Bearer access_token' header. 
Use the access token that you retrieved from Login. 
Keep in mind that access tokens expire after 15 minutes. 
You may request a fresh access token by sending a POST request to https://freddy.codesubmit.io/refresh' with the 'Authorization: Bearer refresh_token' header.

我还没有完成刷新令牌部分,因为我不确定怎么做,我想这可能是问题所在?由于令牌过期而超时?

这是我的登录信息:

import React, {useContext, useState} from 'react';
import { useHistory } from 'react-router-dom'
import axios from 'axios';
import { AuthContext } from '../hooks/UserContext';
import Logo from '../images/Freddys_Logo.svg';
import '../css/Login.css';
  
const Login = () => {
  const [userError, setUserError] = useState("");
  const [passError, setPassError] = useState("");
  const {setLoggedIn} = useContext(AuthContext);
  let history = useHistory();
  const [authInfo, setAuthInfo] = useState({
    username: "",
    password: ""
  })

  const handleChange = e => {
    setAuthInfo({
      ...authInfo,
      [e.target.name]: e.target.value
    })
  }

  const handleSubmit = e => {
    e.preventDefault();
    axios.post('https://freddy.codesubmit.io/login', authInfo)
      .then(res => {
        setLoggedIn(true);
         localStorage.setItem("token", res.data.access_token);
         localStorage.setItem("refresh_token", res.data.refresh_token);
         history.push('/dashboard')
      })
      .catch(err => console.log(err))
  }

 return (
  <div className="wrapper">
    <div className="logoContainer">
    <div className="heading">
       <p>
         Freddy's
         <br/>
        Artisanal
        <br/>
        Halloween
        <br/>
        Candy Shop
       </p>
    </div>
      <div className="svgLogo">
        <img src={Logo} className="svgLogo" alt="image" />  
      </div>
    </div>
    <div className="inputContainer">
    <form method="POST" onSubmit={handleSubmit}>
      <input 
        name="username" 
        type="text" 
        value={authInfo.username} 
        placeholder="username" 
        onChange={handleChange} 
        className="input" 
      />
      <input 
        name="password" 
        type="password" 
        value={authInfo.password} 
        placeholder="************" 
        onChange={handleChange}  
        className="input" 
      />
      <input 
        type="submit"  
        value="Login" 
        className="submitButton"
      />
    </form>
    </div>
    ElmStreet2019
  </div>
 )
}

export default Login;

这是我用来获取数据的 api:useFetch.js

import { useEffect, useState } from "react";
import axios from "axios";
const useFetch = async => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState(null);

  const token = localStorage.getItem("token");

  useEffect(() => {
    async function fetchData() {
      try {
        const res = await axios.get(
          "https://freddy.codesubmit.io/dashboard"
        , {headers: {Authorization: `Bearer ${token}`}});

        setResponse(res);
      } catch (error) {
        setError(error, "err");
      }
    }

    fetchData();
  }, [token]);
  return { response, error };
};
export default useFetch;

这是我尝试显示数据的页面:Dashboard.jsx

import React, {useState, useContext, useEffect} from 'react';
import Layout from './Layout';
import Table from './Table';
import axios from 'axios';
import { useHistory } from 'react-router-dom'
import { AuthContext } from '../hooks/UserContext'
import useFetch from "../hooks/useFetch";
import Switch from "react-switch";
import BarChart from 'react-bar-chart';

import '../css/Dashboard.css'

const Dashboard = () => {
  const {} = useContext(AuthContext);
  const { response, error } = useFetch();
  const [checked, setChecked] = useState(false);
  const refreshToken = localStorage.getItem("refresh_token")


  const handleCheckedChange = () => {
    setChecked(!checked)
  }

  const lastSevenDays = [
    {text: 'yesterday', value: 500}, 
    {text: 'today', value: 1300},
    {text: 'day 3', value: 300},
    {text: 'day 4', value: 300}, 
    {text: 'day 5', value: 300},
    {text: 'day 6', value: 300}, 
    {text: 'day 7', value: 300}, 
  ];
  const lastTwelveMonths = [
    {text: 'this month', value: 500}, 
    {text: 'today', value: 1300},
    {text: 'day 3', value: 300},
    {text: 'day 4', value: 300}, 
    {text: 'day 5', value: 300},
    {text: 'day 6', value: 300}, 
    {text: 'day 7', value: 300}, 
  ];
  const margin = {top: 10, right: 20, bottom: 30, left: 40};

  console.log(error)

 return (
    <Layout>
        <h1>Dashboard</h1>
        <div className="container">
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
          <div className="item">
            <span className="textStyle">Today</span>
            <p>$1456 / 9 orders</p>
          </div>
        </div>

        <div className="revenueContainer">
          <div className="title">
          {!checked ? <h2>Revenue (last 7 days)</h2> : <h2>Revenue (last 12 months)</h2>}
          </div>
          <div className="toggle">
            <Switch 
              onChange={handleCheckedChange} 
              checked={checked} 
              onColor="#86d3ff"
              onHandleColor="#2693e6"
              uncheckedIcon={false}
              checkedIcon={true}
              boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)"
              activeBoxShadow="0px 0px 1px 10px rgba(0, 0, 0, 0.2)"
            />
          </div>
        </div>

        <div>
            <div style={{width: '100%'}}> 
            {!checked ? (
              <BarChart 
                ylabel=''
                width={600}
                height={300}
                margin={margin}
                data={lastSevenDays}
              />
              ) : !!checked ? (
                <BarChart 
                ylabel=''
                width={600}
                height={300}
                margin={margin}
                data={lastTwelveMonths}
              />
              ) : null}
            </div>
          </div>

        <h2>Bestsellers</h2>
        <Table bestsellers={response.data.dashboard.bestsellers} /> 
    </Layout>
 )
}

export default Dashboard;

Dashboard.js 中的表格组件

import React from 'react';
import '../css/Table.css';

const Table = ({bestsellers}) => {
  if(bestsellers === undefined || null) {
    return <div> loading...</div>
  }
  return (
    <div className="tableContainer">
      <div className="headingContainer">
        <div className="tableHeader"><span className="tableHeading">Product Name</span></div>
          <div className="tableHeader"><span className="tableHeading">Price</span></div>
          <div className="tableHeader"><span className="tableHeading"># Units Sold</span></div>
          <div className="tableHeader"><span className="tableHeading">Revenue</span></div>
      </div>
      {bestsellers
         .slice(0, 3)
         .map(row => (
        <div className="rowContainer" key={row.product.id}> 
          <div className="tableItem">
            <span className="tableItemText">{row.product.name}</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">N/A</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">{row.units}</span>
          </div>
          <div className="tableItem">
            <span className="tableItemText">{row.revenue}</span>
          </div>
        </div>
      ))}
    </div>
  )
}

export default Table;
1个回答

您的 useFetch 钩子最初返回 null 作为 response 。在 Dashboard 组件中,您尝试将 response.data.dashboard.bestsellers 传递给 Table 组件,而不检查 response 是否不为 null / undefined

根据您的开发环境的现代程度,您可以编写:

<Table bestsellers={response && response.data.dashboard.bestsellers} />

或:

<Table bestsellers={response?.data.dashboard.bestsellers} />
Wojciech Maj
2021-03-04