好的,假设我在Redux store中有一个初始状态,如下所示:
const initialState = {
userReports: [],
activeReport: null,
}
userReports是一个报告列表。activeReport是那些报告中的一个(正在被积极地使用的报告)。
我希望活动报表指向数组中的一个。换句话说,如果我修改活动报表,它将修改userReports数组中的报表。这意味着,两个对象必须指向相同的内存空间。这很容易设置。
此方法的替代方法是复制userReports数组中的一个报告,并将其设置为活动报告(现在它具有不同的内存地址)。现在的问题是,当我编辑activerport时,我还必须搜索userReports数组,找到与活动报告相似的报告并在那里修改它。这感觉很啰嗦。
问题是:
让activeReport指向数组中的报告(相同对象)会是不好的做法吗?当我想要更改报告时,我可以这样做(示例是使用redux thunk):
export const updateReport = (report) => async (dispatch, getState) => {
try {
const report = getState().reports.activeReport
// modify the active report here
report.title = "blah blah blah"
dispatch({ type: ACTIONS.UPDATE_REPORT, payload: report })
} catch (error) {
console.log(`ERROR: ${error.message}`)
}
}
在我的减速器中:
case ACTIONS.UPDATE_REPORT:
return { ...state, activeReport: action.payload }
如您所见,在更新报告之后,我仍然返回一个"新版本"。该方法还会更新userReports数组中的报告,因为它们指向相同的内存地址。
我想说这并不理想,报告有id吗?如果他们这样做,我宁愿将userReports保存在一个对象中,键作为id,然后活动报告可以只是一个id并重命名为activeReportId,这样你就可以通过userReports[activeReportId]获取activeReport
你还问了原因:
所以首先任何屏幕看userReports不会渲染,因为报告没有被重新分配。
其次,如果有人以后想要更新这些屏幕,他们将重新分配userReports,这可能会导致问题。
第三,它是一个不寻常的模式,这对redux来说是一个巨大的禁忌。redux的关键是它有一个非常明显的模式,所以当你添加东西时,你不需要思考,可以自信地进行更改。
您的activeReport
不应该指向userReports
数组中的对象,而应该是用户当前正在处理的报告的id
。userReports
中的每个报告都有一个唯一的id
字段来标识报告-这在react中呈现时很有帮助-这个id
字段可以用作键。
那么你的动作创建器/调度程序将看起来像这样:
export const updateReport = (updatedReport) => async (dispatch, getState) => {
dispatch({ type: ACTIONS.UPDATE_REPORT, payload: updatedReport });
}
你将在你的组件中调用它:
const onTitleChangeHandler = (e) => {
var newTitle = e.target.value;
// you will get the userReports and activeReport from props or by using some redux selector, also you will need to get dispatch and getState from redux
var activeReportObj = userReports.filter((r) => r.id === activeReport)[0];
updateReport({ title: newTitle, ...activeReportObj })(dispatch, getState);
}
最后,您的减速器将是:
case ACTIONS.UPDATE_REPORT:
var newUserReports = state.userReports.map((r) => {
if (r.id === state.activeReport) {
return action.payload;
}
return r;
});
return { newUserReports, ...state };