我正在使用Context API进行电子商务React应用程序中的登录功能。 因此,当用户键入他的电子邮件和密码时,该电子邮件和密码将调用reducer中的操作以检查该数据并将用户数据设置为Context Provider中的状态。
这是行动(我省略了其他可行的案例):
const reducer = (state, action) => {
...
switch(action.type) {
case 'USER_LOGIN':
let user = userLogin(state.user,action.payload);
return {
...state,
user: user,
loggedIn: temp.length> 0 ? true: false
};
...
这是函数userLogin()
,它本身可以正常工作,并返回漂亮的用户数据数组。
var userLogin = (user, payload) => {
const url = "/api/users/login.php";
console.log(payload);
fetch(url,{
method: "POST",
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(
(result) => {
user.id = result.id;
user.name = result.name;
user.email = result.email;
user.phone = result.phone;
user.city = result.city;
user.street = result.street;
user.building = result.building;
user.flat = result.flat;
},
(error) => {
console.log(error);
});
return user;
}
但是当导致我的<Provider>
时,状态user
保留为初始化后的空数组。
我认为有些东西必须与fetch()
的异步类型一起使用,但是找不到任何参考。
UPD:这是我的<Login>
组件
import React, { Component } from 'react'
import {Consumer} from '../../Context'
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
};
}
userLogin = (dispatch, e) => {
e.preventDefault();
dispatch({
type: 'USER_LOGIN',
payload: {email: this.state.email,
password: this.state.password }
});
}
handleChange = (e) => {
this.setState({
[e.target.name] : e.target.value
})
}
render() {
return (
<Consumer>
{
value=> {
const {dispatch} = value;
return (
<div className="checkout__container">
<h5 className="checkout__header">Login</h5>
<form>
<label className="checkout__label">E-mail:</label><br />
<input className="checkout__input" type="email" name="email" onChange={this.handleChange}></input><br /><br />
<label className="checkout__label">Password:</label><br />
<input className="checkout__input" type="password" name="password" onChange={this.handleChange}></input><br /><br />
<button type="button" className="button button-primary" onClick={this.userLogin.bind(this, dispatch)}>Sign In</button>
</form>
</div>
);
}
}
</Consumer>
)
}
}
UPD#2:这是我的Context.js
中包含Provider
组件的摘录
import React, { Component } from 'react'
import axios from 'axios'
const Context = React.createContext();
const reducer = (state, action) => {
...
switch(action.type) {
case 'USER_LOGIN':
let user = userLogin(state.user,action.payload);
return {
...state,
user: user
};
};
};
var userLogin = (user, payload) => {
// Do fetch() here and return user array
}
...
class Provider extends Component {
constructor(props) {
super(props);
this.state = {
user: [],
loggedIn: false,
dispatch: action => this.setState( state => reducer(state,action))
};
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
const Consumer = Context.Consumer;
export {Provider, Consumer};
答案 0 :(得分:0)
您的代码存在问题
var userLogin = (user, payload) => {
//...
fetch(url,{
method: "POST",
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(
(result) => {
user.id = result.id;
user.name = result.name;
// ...
},
(error) => {
console.log(error);
});
return user;
}
您致电fetch
,返回Promise。解决Promise后,将调用传递到then
的回调。但是userLogin
直到解决Promise才会停止执行。因此,在fetch
被调用之后,userLogin
返回了。但是user
当时没有改变。未收到响应,Promise未解决。
当响应到来时,user
将被更改,但是return
语句已被执行,因此将不会返回任何内容。
纠正此问题的唯一方法是遵循Redux的思想,并将异步代码移至动作创建者。在您的情况下,动作创建者是来自userLogin
组件的Login
,并使减速器代码完全同步。您也可以从userLogin
组件中移出Login
方法。
例如
userLogin = (dispatch, e) => {
e.preventDefault();
let payload = {email: this.state.email,
password: this.state.password };
const url = "/api/users/login.php";
console.log(payload);
fetch(url,{
method: "POST",
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(
(result) => {
user.id = result.id;
user.name = result.name;
// ...
// And call dispatch from here
dispatch (type: 'USER_LOGIN',
user: user // We don't need payload here as we already got user info
);
},
(error) => {
console.log(error);
});
}
并根据需要修改减速器
const reducer = (state, action) => {
//...
switch(action.type) {
case 'USER_LOGIN':
return {
...state,
user: [...user, action.user]; // user is array so add new user to existing array
};
};
}