这是一个冗长的解释。尽可能简短:我有两个组件Employees
和AddEmployee
- 它们分别附加到路由/employees
和employees/add
。 Employee
组件中的链接会将employees/add
推送到BrowserHistory,反之亦然(AddEmployee
组件也会在表单成功提交后推送/employees
,或者如果是用户点击'取消')。
如果我导航到/employees
,组件工作正常。如果我点击导航到/employees/add
, 组件正常工作。如果我点击“取消”或提交表单以重定向回/employees
...组件会中断。
通过大量调试,我确定这是因为AddEmployee
的redux状态持续到Employee
。我的猜测是因为他们都使用相同的传奇。我编写了一个get
Redux saga来处理对远程API的请求。 Employees
显然使用get
传奇来检索所有用户,而AddEmployee
使用get
传奇来检索可能分配给用户的位置。
加载Employees
时,apiGet
saga的状态包含检索到的员工。加载AddEmployee
时,apiGet
saga的状态包含检索到的位置。然后,当您将返回导航到Employees
时,apiGet
saga 的状态仍然包含检索到的位置,并且它不会再次运行以加载员工再次。
我该如何解决这个问题?
我已尽力将下面的代码压缩到相关部分。
get
佐贺:
function getApi(endpoint, token) {
return fetch(apiUrl + endpoint, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
}
}).then(handleApiErrors)
.then(response => response.json())
.catch((error) => {throw error})
}
function* apiGetFlow(endpoint) {
let response, token
try {
token = localStorage.getItem('token')
token = JSON.parse(token)
response = yield call(getApi, endpoint, token)
yield put({ type: CLIENT_GET_SUCCESS, response: response })
} catch(error) {
...
}
return response
}
function* apiGetWatcher() {
while(true) {
const { endpoint } = yield take(CLIENT_GET_REQUESTING)
const task = yield fork(apiGetFlow, endpoint)
}
}
export default apiGetWatcher
Employees
组件:
class Employees extends Component {
componentDidMount() {
this.usersGet()
}
usersGet() {
this.props.apiGetRequest('users')
}
render() {
...
}
}
const mapStateToProps = state => {
return {
users: state.apiGet,
}
}
const connected = connect(mapStateToProps, { apiGetRequest })(Employees)
export default connected
AddEmployee
组件:
class AddEmployeeForm extends Component {
componentDidMount() {
this.locationsGet()
}
locationsGet() {
this.props.apiGetRequest('locations')
}
render() {
...
}
}
const mapStateToProps = state => {
return {
locations: state.apiGet,
save: state.apiPost,
}
}
const formed = reduxForm({
form: 'addemployee',
})(AddEmployeeForm)
const connected = connect(mapStateToProps, { apiGetRequest, apiPostRequest })(formed)
export default connected
答案 0 :(得分:0)
我怀疑它是因为你的React组件没有卸载。看起来这些组件从componentDidMount
生命周期方法中激活了它们的api请求。
假设您从/employees/
开始,Employees
组件已安装并为用户分派api请求。
当您导航到/employees/add
时,AddEmployeeForm
组件会安装并调度位置的api请求。
当您向后按,现在回到/employees
时,Employees
组件已经安装。因此,它不会再次针对用户'
您可以通过使用console.log在每个组件中实现componentWillUnmount
方法来验证这是否是问题。
话虽如此,在我看来,你不应该在期望数据完全不同的组件之间共享state.apiGet
缩减器。不同的数据应该在我们的减速器中保持状态。
假设您重新构建了组件,以便在来回时成功分派API请求,并state.apiGet
进行相应更新。这真的是你想要的吗?每次用户按下前进和后退时,API响应会不同吗?此外,api请求会有延迟,state.apiGet
最初会有错误的数据,直到请求完成。
我会创建一个users
减速器和一个locations
减速器。然后创建两个包含getApi
方法的传奇,并发送他们的特定操作。
例如:
function* getUsers(endpoint) {
let response, token
try {
token = localStorage.getItem('token')
token = JSON.parse(token)
response = yield call(getApi, endpoint, token)
yield put({ type: 'ADD_USERS', response: response })
} catch(error) {
...
}
return response
}
并且
function* getLocations(endpoint) {
let response, token
try {
token = localStorage.getItem('token')
token = JSON.parse(token)
response = yield call(getApi, endpoint, token)
yield put({ type: 'ADD_LOCATIONS', response: response })
} catch(error) {
...
}
return response
}
在您的组件中:
const mapStateToProps = state => {
return {
users: state.users,
}
}
const mapStateToProps = state => {
return {
locations: state.locations,
save: state.apiPost,
}
}
Official Redux文档中有关于如何创建单独的缩减器的详细信息。