Reactjs 带有fetch()的上下文API缩减器不';更新状态
我正在使用上下文API开发电子商务应用程序中的登录函数。 所以当用户在他的电子邮件和密码中键入时,就会调用reducer中的操作来检查该数据,并在上下文提供程序中将用户数据设置为状态 以下是行动(我正在推荐其他有效的案例): 下面是函数Reactjs 带有fetch()的上下文API缩减器不';更新状态,reactjs,react-redux,fetch,react-context,Reactjs,React Redux,Fetch,React Context,我正在使用上下文API开发电子商务应用程序中的登录函数。 所以当用户在他的电子邮件和密码中键入时,就会调用reducer中的操作来检查该数据,并在上下文提供程序中将用户数据设置为状态 以下是行动(我正在推荐其他有效的案例): 下面是函数userLogin(),它本身工作正常,并返回一个漂亮的用户数据数组 var userLogin = (user, payload) => { const url = "/api/users/login.php"; console.log(payl
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;
}
但是,在结果为my
时,user
的状态值在初始化时保持为空数组
我认为有一些东西必须使用异步类型的fetch()
,但找不到任何相关参考
UPD:这是我的
组件
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>
)
}
}
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};
代码的问题就在这里
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
,它返回承诺。当承诺被解析时,将调用传递给的回调,然后调用。但在承诺得到解决之前,userLogin
不会停止执行。因此,在调用fetch
之后,userLogin
返回。但是,用户
当时没有改变。未收到响应,承诺未得到解决
当响应到来时,user
将被更改,但return
语句已经执行,所以不会返回任何内容
纠正这种情况的唯一方法是遵循Redux的思想,将异步代码移动到ActionCreator。在您的例子中,操作创建者是来自Login
组件的userLogin
,并使reducer代码完全同步。您还可以将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
};
};
}
代码的问题就在这里
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
,它返回承诺。当承诺被解析时,将调用传递给的回调,然后调用。但在承诺得到解决之前,userLogin
不会停止执行。因此,在调用fetch
之后,userLogin
返回。但是,用户
当时没有改变。未收到响应,承诺未得到解决
当响应到来时,user
将被更改,但return
语句已经执行,所以不会返回任何内容
纠正这种情况的唯一方法是遵循Redux的思想,将异步代码移动到ActionCreator。在您的例子中,操作创建者是来自Login
组件的userLogin
,并使reducer代码完全同步。您还可以将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
};
};
}
fetch
是async
。因此userLogin()
会立即返回,而不会更改user
对象。我认为减速器不是异步加载数据的合适位置。使用类似于thunk
、saga
或observatives
的方法来处理副作用。thunk
和saga
使用Redux
,而observatives
指的是RxJS
。有没有一种方法可以使用Context-API
实现async
fetch
?为什么不能fetch
然后dispatch
操作?@asafavi我根本不使用Redux
,只使用Context-API
。在上面添加了
组件我认为我应该使用useffect()
钩子来实现我的userLogin()
函数fetch
是async
。因此userLogin()
会立即返回,而不会更改user
对象。我认为减速器不是异步加载数据的合适位置。使用类似于thunk
、saga
或observatives
的方法来处理副作用。thunk
和saga
使用Redux
,而observatives
指的是RxJS
。有没有一种方法可以使用Context-API
实现async
fetch
?为什么不能fetch
然后dispatch
操作?@asafavi我根本不使用Redux
,只使用Context-API
。在上面添加了
组件我认为我应该为我的userLogin()
函数使用useffect()
钩子谢谢,现在我将用户数组传递给reducer
,但是状态
设置为空数组,而不是操作。user
<代码>案例“用户\登录”:返回{…状态,用户:action.USER}代码>我将用户
替换为操作。用户
因为它是登录的用户,所以应该只有一个。在调度呼叫之前,用户
的内容是什么?我尝试了两种方法:用户:[]
和用户:未定义的
在提供者
状态
中。第一个在dispatch
之后不会改变,第二个将user
设置为空数组,并将传递给dispatch的内容设置为空数组,这一点非常重要。在调用dispatch之前,请console.log(user)
在调用dispatch之前user
是一个数组,其中包含从数据库返回的正确用户数据。当reducer()中的console.log(action.user)
时也是如此。谢谢,现在我将用户数组传递给reducer
,但是state
设置为空数组,而不是action.user
<代码>案例“用户\登录”:返回{…状态,用户:action.USER}代码>我将用户
替换为操作。用户
因为它是登录的用户,所以应该只有一个。在调度呼叫之前,用户
的内容是什么?我尝试了两种方法:用户:[]
和用户:未定义的
在提供者
状态
中。第一个在dispatch
之后不会改变,第二个将user
设置为空数组,并将传递给dispatch的内容设置为空数组,这一点非常重要。请输入密码