Redux thunk——正确的实现
Redux thunk – Proper implementation
我的 redux thunk 实现导致覆盖数组数据。
显然流程中出了点问题,但我想不通。
基本上我有两个组件 StringInstrument 和 UsersListedItems。
StringInstrument 将从数据库中获取数据(通过 axios)以获取项目所有者列表。
将为每个所有者创建一个 UsersListedItems 组件,该组件还将通过所有者 ID 从数据库(图像)中获取数据。
所以我会说 StringInstrument 实际上创建了 UsersListedItems.
这是 StringInstrument 的一些代码:
if (this.props.error) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <CircularProgress/>;
}
return (
<div>
<Grid container spacing={24}>
{this.props.itemOwner.map((item, index) => (
<Grid item xs={6} sm={3} key={index}>
<UsersListedItems
ownerId={item.ownerId}
userName={item.userName}
categoryId={1}>
</UsersListedItems>
</Grid >)
)}
</Grid>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
itemOwner: state.itemOwner.data,
isLoading: state.itemOwner.isLoading,
error: state.itemOwner.error
}
}
const mapDispatchToProps = (dispatch) => {
return {
getItemOwners: (id) => dispatch(itemAction.getItemOwners(id))
}
这就是我实现 action 和 reducer 的方式。
export function getItemOwner(state = initState, action) {
switch (action.type) {
case GET_ITEM_OWNER_START:
state = Object.assign({}, state, { isLoading: true });
break;
case GET_ITEM_OWNER_SUCCESS:
state = Object.assign({}, state, { data: action.payload, isLoading: false });
break;
case GET_ITEM_OWNER_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
return state;
}
export function getItems(state = initState, action) {
switch (action.type) {
case GET_ITEMS_START:
state = Object.assign({}, state, { isLoading: true });
break;
case GET_ITEMS_SUCCESS:
state = Object.assign({}, state, { data: action.payload, isLoading: false });
break;
case GET_ITEMS_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
return state;
export const getItemOwners = (categoryId) => {
return (dispatch, getState) => {
//make async call to database
dispatch({ type: GET_ITEM_OWNER_START });
axios.get('api/items/owner/category/' + categoryId)
.then(function (response) {
dispatch({ type: GET_ITEM_OWNER_SUCCESS, payload: response.data });
})
.catch(function (error) {
dispatch({ type: GET_ITEM_OWNER_ERROR, payload: error });
});
}
};
export const getItems = (categoryId, ownerId) => {
return (dispatch, getState) => {
dispatch({ type: GET_ITEMS_START });
axios.get('api/items/' + categoryId + '/' + ownerId)
.then(function (response) {
dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data });
})
.catch(function (error) {
dispatch({ type: GET_ITEMS_ERROR, payload: error });
});
}
我不确定如何 manage\control 调度程序的流程以便它适合组件结构而不覆盖收集的数据。
正如您在附件图片中看到的那样,4 个 'GET_ITEM_SUCCESS' 在末尾,每个都将覆盖下一个。
希望我已经清楚并为这个长代码示例道歉。
谢谢
我认为您遇到的问题是您在任何给定时间仅将其中一项存储在状态中,并且每个后续调用都会破坏状态中的内容。如果我的假设是正确的,那么解决方案是使用 categoryId 和 ownerId 作为将数据存储在对象中的键,其中值将是有效负载。
首先您需要在操作中提供 categoryId 和 ownerId
export const getItems = (categoryId, ownerId) => (dispatch, getState) => {
dispatch({ type: GET_ITEMS_START, categoryId, ownerId });
axios.get('api/items/' + categoryId + '/' + ownerId)
.then(function (response) {
dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data, categoryId, ownerId });
})
.catch(function (error) {
dispatch({ type: GET_ITEMS_ERROR, payload: error, categoryId, ownerId });
});
接下来,您需要更新减速器以将负载分配给对象
const key = `${action.categoryId}-${action.ownerId}`; // unique key for the payload
switch (action.type) {
case GET_ITEMS_START:
state = Object.assign({}, state, { isLoading: true, data: Object.assign({}, state.data, {[key]: []}) });
break;
case GET_ITEMS_SUCCESS:
state = Object.assign({}, state, { data: Object.assign({}, state.data, { [key]: action.payload }), isLoading: false });
break;
case GET_ITEMS_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
最后,您需要通过 props (redux) 将数据映射到组件的状态。然后您可以使用相同的密钥项访问项目[${categoryId}-${ownerId}
]
我的 redux thunk 实现导致覆盖数组数据。
显然流程中出了点问题,但我想不通。
基本上我有两个组件 StringInstrument 和 UsersListedItems。
StringInstrument 将从数据库中获取数据(通过 axios)以获取项目所有者列表。
将为每个所有者创建一个 UsersListedItems 组件,该组件还将通过所有者 ID 从数据库(图像)中获取数据。
所以我会说 StringInstrument 实际上创建了 UsersListedItems.
这是 StringInstrument 的一些代码:
if (this.props.error) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <CircularProgress/>;
}
return (
<div>
<Grid container spacing={24}>
{this.props.itemOwner.map((item, index) => (
<Grid item xs={6} sm={3} key={index}>
<UsersListedItems
ownerId={item.ownerId}
userName={item.userName}
categoryId={1}>
</UsersListedItems>
</Grid >)
)}
</Grid>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
itemOwner: state.itemOwner.data,
isLoading: state.itemOwner.isLoading,
error: state.itemOwner.error
}
}
const mapDispatchToProps = (dispatch) => {
return {
getItemOwners: (id) => dispatch(itemAction.getItemOwners(id))
}
这就是我实现 action 和 reducer 的方式。
export function getItemOwner(state = initState, action) {
switch (action.type) {
case GET_ITEM_OWNER_START:
state = Object.assign({}, state, { isLoading: true });
break;
case GET_ITEM_OWNER_SUCCESS:
state = Object.assign({}, state, { data: action.payload, isLoading: false });
break;
case GET_ITEM_OWNER_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
return state;
}
export function getItems(state = initState, action) {
switch (action.type) {
case GET_ITEMS_START:
state = Object.assign({}, state, { isLoading: true });
break;
case GET_ITEMS_SUCCESS:
state = Object.assign({}, state, { data: action.payload, isLoading: false });
break;
case GET_ITEMS_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
return state;
export const getItemOwners = (categoryId) => {
return (dispatch, getState) => {
//make async call to database
dispatch({ type: GET_ITEM_OWNER_START });
axios.get('api/items/owner/category/' + categoryId)
.then(function (response) {
dispatch({ type: GET_ITEM_OWNER_SUCCESS, payload: response.data });
})
.catch(function (error) {
dispatch({ type: GET_ITEM_OWNER_ERROR, payload: error });
});
}
};
export const getItems = (categoryId, ownerId) => {
return (dispatch, getState) => {
dispatch({ type: GET_ITEMS_START });
axios.get('api/items/' + categoryId + '/' + ownerId)
.then(function (response) {
dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data });
})
.catch(function (error) {
dispatch({ type: GET_ITEMS_ERROR, payload: error });
});
}
我不确定如何 manage\control 调度程序的流程以便它适合组件结构而不覆盖收集的数据。
正如您在附件图片中看到的那样,4 个 'GET_ITEM_SUCCESS' 在末尾,每个都将覆盖下一个。
希望我已经清楚并为这个长代码示例道歉。
谢谢
我认为您遇到的问题是您在任何给定时间仅将其中一项存储在状态中,并且每个后续调用都会破坏状态中的内容。如果我的假设是正确的,那么解决方案是使用 categoryId 和 ownerId 作为将数据存储在对象中的键,其中值将是有效负载。
首先您需要在操作中提供 categoryId 和 ownerId
export const getItems = (categoryId, ownerId) => (dispatch, getState) => {
dispatch({ type: GET_ITEMS_START, categoryId, ownerId });
axios.get('api/items/' + categoryId + '/' + ownerId)
.then(function (response) {
dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data, categoryId, ownerId });
})
.catch(function (error) {
dispatch({ type: GET_ITEMS_ERROR, payload: error, categoryId, ownerId });
});
接下来,您需要更新减速器以将负载分配给对象
const key = `${action.categoryId}-${action.ownerId}`; // unique key for the payload
switch (action.type) {
case GET_ITEMS_START:
state = Object.assign({}, state, { isLoading: true, data: Object.assign({}, state.data, {[key]: []}) });
break;
case GET_ITEMS_SUCCESS:
state = Object.assign({}, state, { data: Object.assign({}, state.data, { [key]: action.payload }), isLoading: false });
break;
case GET_ITEMS_ERROR:
state = Object.assign({}, state, { error: action.payload, isLoading: false });
break;
}
最后,您需要通过 props (redux) 将数据映射到组件的状态。然后您可以使用相同的密钥项访问项目[${categoryId}-${ownerId}
]