我刚刚开始学习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;
}
答案 0 :(得分:1)
默认情况下,processInt(parameter)
是未定义的。为了填充它,您需要告诉react用它填充什么。假设您在react 16.6 or later上,则看起来像这样:
this.context