AJAX调用后无法在ReactJS上下文API中设置状态

时间:2019-04-19 15:53:56

标签: javascript reactjs state-management

我刚刚开始学习ReactJS,我决定在ReactJS中使用新的上下文API来管理我正在学习的项目中的状态。

这是context.js代码,

import React, { Component } from "react";
import axios from "axios";

const Context = React.createContext();

const reducer = async (state, action) => {
  switch (action.type) {
    case "USER_LOGIN":
      const { token } = action.payload;

      return { ...state, user: { token } };

    case "GET_USER_DATA":
      const url = "api/users/dashboard";
      const userToken = action.payload.token;

      let res = await axios.get(url, {
          headers: {
            Authorization: userToken
          }
      })


      let urls = res.data.urls;
      urls = urls.map(url => ( { ...url,shortUrl: axios.defaults.baseURL + "/" + url.urlCode} ) )

      return { ...state, user: { token } };

  }
};

export class Provider extends Component {
  state = {
    user: {
      token: "",
      data: [{id: 'adsasd'}]
    },
    dispatch: action => {
      this.setState(state => reducer(state, action));
    }
  };


  render() {
    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    );
  }
}

export const Consumer = Context.Consumer;

我有两种类型的操作,一种是登录,另一种是根据成功登录后收到的JWT令牌获取用户数据。

这是我的登录组件

import React, { Component } from "react";
import { Row, Col, Input, Icon, CardPanel, Button } from "react-materialize";
import axios from 'axios'
import { Consumer } from '../store/context'

class Login extends Component {
  state = {
    errors: {
      name: "",
      password: ""
    }
  };

  constructor(props) {
    super(props);
    this.emailInputRef = React.createRef();
    this.passwordInputRef = React.createRef();
  }


  login = async (dispatch) => {
    const email = this.emailInputRef.state.value;
    const password = this.passwordInputRef.state.value;

    if (typeof password != "undefined" && password.length < 6) {
      this.setState({ errors: { password: "Password length must be atleast 6 characters!" } })
    }
    else {
      this.setState({ errors: { password: "" } })
    }

    if (typeof email != "undefined") {
      if (!validateEmail(email)) {
        console.log('invalid email');

        this.setState({ errors: { email: "Invalid email address!" } })
      }
      else {
        this.setState({ errors: { email: "" } })
      }
    }
    else {
      this.setState({ errors: { email: "Invalid email address!" } })
    }

    // console.log(this.state.errors);

    if ((email !== "" || typeof email !== "undefined") && (password !== "" || typeof password !== "undefined")) {

      const res = await axios.post('/api/users/login', {
        'email': email,
        'password': password
      })


      dispatch({
        type: 'USER_LOGIN',
        payload: {
          token: res.data.data.token
        }
      })

      this.props.history.push('/dashboard')


    }

  }

  render() {
    const { errors } = this.state;
    return (
      <Consumer>
        {value => {

          const { dispatch } = value

          return (
            <CardPanel className="bg-primary" style={{ padding: "20px 5%" }}>
              <Row className="login">
                <h1 style={{ color: "white" }}>Login</h1>
                <Col s={12} m={12}>
                  <Input
                    s={12}
                    m={12}
                    name="email"
                    error={errors.email}
                    className="error"
                    label="Email"

                    ref={ref => this.emailInputRef = ref}
                  >
                    <Icon>account_circle</Icon>
                  </Input>

                  <Input
                    s={12}
                    m={12}
                    name="password"
                    error={errors.password}
                    label="Password"

                    type="password"
                    ref={ref => this.passwordInputRef = ref}
                  >
                    <Icon>lock</Icon>
                  </Input>
                  <Button onClick={this.login.bind(this, dispatch)} style={{ marginTop: "20px" }} waves="yellow">
                    Login
                </Button>
                </Col>
              </Row>
            </CardPanel>
          )
        }}

      </Consumer>

    );
  }
}

function validateEmail(sEmail) {
  const reEmail = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/

  if (sEmail === "") return false;

  return reEmail.test(sEmail);
}

function isEmpty(obj) {
  if (obj == null) return true;
  return Object.entries(obj).length === 0 && obj.constructor === Object;
}

export default Login;

我想要实现的是,当用户尝试登录时,我向后端发出请求并接收JWT令牌,然后在context.js中调度登录操作以存储该令牌以备将来使用。之后,我将用户重定向到仪表板,在那里他可以获取他生成的数据。为了获取数据,我再次向后端发出AJAX请求,并在上下文中存储了JWT令牌。我在componentDidMount()方法中执行此操作,但是当我尝试访问上下文数据时,总是收到空对象。这是仪表板

Dashboard.jsx

   import React, { Component } from 'react'
import axios from 'axios'
import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
import BootstrapTable from 'react-bootstrap-table-next';
import overlayFactory from 'react-bootstrap-table2-overlay';

import { Consumer } from '../store/context'

const columns = [
    {
        dataField: 'url',
        text: 'URLs'
    },

    {
        dataField: 'hits',
        text: 'Hits'
    },
    {
        dataField: 'shortUrl',
        text: 'Short URL'
    },
    {
        dataField: 'createdDate',
        text: 'Date'
    },
];

export default class Dashboard extends Component {

    state = {
        data: []
    }

    componentDidMount() {

        // const url = 'api/users/dashboard'

        const context = this.context

        console.log(context); // always empty

    }

    render() {
        return (
            <Consumer>
                {value => {
                    const { user } = value

                    return (
                        isEmpty(user) ? <h3 className="center-align">Please Login To View Dashboard...</h3> : (
                            < BootstrapTable keyField='shortUrl'
                                data={this.state.data}
                                columns={columns}
                                bordered={true}
                                hover={true}
                            />
                        )
                    )

                }}
            </Consumer>
        )
    }
}

function isEmpty(obj) {
    if (obj == null) return true;
    return Object.entries(obj).length === 0 && obj.constructor === Object;
}

1 个答案:

答案 0 :(得分:1)

默认情况下,processInt(parameter)是未定义的。为了填充它,您需要告诉react用它填充什么。假设您在react 16.6 or later上,则看起来像这样:

this.context