reactjs - redux-toolkit 中的多次调度问题
问题描述
我需要使用 redux-toolkit 一个一个(不是并行)运行 call 3 dispatch。在调试期间它工作正常,但在运行时它给了我一个奇怪的错误。
代码:
dispatch(pointUpdateAll(items));
// dispatch(pathUpdateOne({ id: path_id, changes: { wps: wps } }));
dispatch(
pathUpdateOne({
id: path_id,
// changes: { wps: wps, sumdist: new_sum_dist },
changes: { wps: wps, sumdist: new_sum_dist },
})
);
dispatch(pointRemove(point_id));
错误:
Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement. EDIT:
整个组件:
import * as Cesium from "cesium";
import { DrawSetting } from "../../../Cesium/DrawConfig";
import React, { useEffect, useContext } from "react";
import { Entity, PointGraphics } from "resium";
import { useSelector, useDispatch, ReactReduxContext } from "react-redux";
import { updateDist } from "./pathutil";
import {
wpsSelectors,
pointUpdateOne,
pointUpdateAll,
pointRemove,
selectPointByPathIDAndOrder,
} from "../../../../../store/slices/wayPoints";
import {
pathUpdateOne,
pathesSelectors,
} from "../../../../../store/slices/pathess";
import {
TogglepathPanel,
SetEditing_path_id,
SetEditable_entity_id,
setFinishEditing,
setEntityNewPosiotion,
} from "../../../../../store/slices/config";
//TODO: remove first point bug
function PointItem({ point_id }) {
const { store } = useContext(ReactReduxContext);
const dispatch = useDispatch();
const point = useSelector((state) =>
wpsSelectors.selectById(state, point_id)
);
const prev_point = selectPointByPathIDAndOrder(
point.path_id,
point.order - 1
)(store.getState())[0];
const next_point = selectPointByPathIDAndOrder(
point.path_id,
point.order + 1
)(store.getState())[0];
// const viewer = useSelector((state) => state.config.cViewer);
const all_points_ids = useSelector((state) => wpsSelectors.selectIds(state));
const ShowPathPanel = useSelector((state) => state.config.ShowPathPanel);
const path = useSelector((state) =>
pathesSelectors.selectById(state, point.path_id)
);
const drawingMode = useSelector((state) => state.config.drawingMode);
// let dragging = undefined;
const editable_entity_id = useSelector(
(state) => state.config.editable_entity_id
);
const is_finish_editing = useSelector((state) => state.config.finish_editing);
// const dragging_id = useSelector((state) => state.config.dragging_id);
const newPosition = useSelector((state) => state.config.entity_new_posiotion);
useEffect(() => {
debugger;
console.log("point changed");
if (point.is_focused) {
dispatch(TogglepathPanel(1));
var ele = document.getElementById("wp" + point.order);
if (
document.getElementsByClassName("pathrow").length > 0 &&
ele !== undefined
) {
document.getElementsByClassName("pathrow")[0].scrollTo({
top: ele.offsetTop,
left: ele.offsetLeft,
behavior: "smooth",
});
}
if (
is_finish_editing &&
editable_entity_id === "path_" + point.path_id + "point_" + point_id
) {
_updateDist(newPosition[0], newPosition[1], newPosition[2]);
dispatch(setEntityNewPosiotion(undefined));
dispatch(setFinishEditing(undefined));
dispatch(SetEditable_entity_id(undefined));
}
}
}, [point, is_finish_editing]);
const _updateDist = (lat, lon, alt) => {
//update dist // update before point distance and path sumdist
let out = updateDist(path, lat, lon, alt, point, next_point, prev_point);
let items = out[0];
let new_sum_dist = out[1];
dispatch(pointUpdateAll(items));
dispatch(
pathUpdateOne({
id: path.id,
changes: { sumdist: new_sum_dist },
})
);
dispatch(
pointUpdateOne({
id: point.id,
changes: { is_focused: false, is_moving: false },
})
);
};
//do focus
const handleOnClick = (pid) => {
if (drawingMode === undefined) {
dispatch(setEntityNewPosiotion(undefined));
dispatch(setFinishEditing(undefined));
dispatch(SetEditable_entity_id(undefined));
console.log("click handler point called");
// if (ShowPathPanel === 0) {
// //open panel
// dispatch(TogglepathPanel(1));
// }
//
dispatch(SetEditing_path_id(point.path_id));
if (ShowPathPanel === 0) {
//open panel
dispatch(TogglepathPanel(1));
}
// defocus all
let items = [];
for (let i = 0; i < all_points_ids.length; i++) {
let item = undefined;
if (all_points_ids[i] !== pid) {
item = {
id: all_points_ids[i],
changes: { is_focused: false },
};
} else {
// focus one and enable move
item = {
id: pid,
changes: { is_focused: true, is_moving: true },
};
}
items.push(item);
}
dispatch(pointUpdateAll(items));
//tell the app which entity is movable
dispatch(
SetEditable_entity_id("path_" + point.path_id + "point_" + point_id)
);
}
};
//delete point
const handleOnRClick = (path_id, point_id) => {
// const wps = path.wps.slice();
let wps = path.wps.slice();
if (wps.length > 2) {
const index = wps.indexOf(point_id);
let after_points_ids = wps.slice(index + 1, wps.length);
if (index > -1) {
wps.splice(index, 1);
}
let order = point.order;
let items = [];
if (after_points_ids.length > 0) {
for (let i = 0; i < after_points_ids.length; i++) {
items.push({ id: after_points_ids[i], changes: { order: order } });
order = order + 1;
}
}
// update before point distance and path sumdist
let new_sum_dist = 0;
let entitys_id_to_remove = [];
switch (index) {
// first point of path
case 0:
new_sum_dist = path.sumdist - point.dist;
entitys_id_to_remove.push("line" + point_id + "_" + next_point.id);
break;
// last point of path
case path.wps.length - 1:
entitys_id_to_remove.push("line" + prev_point.id + "_" + point_id);
new_sum_dist = path.sumdist - prev_point.dist;
items.push({ id: prev_point.id, changes: { dist: 0 } });
break;
//between two points
default:
let new_prev_point_dist = Cesium.Cartesian3.distance(
Cesium.Cartesian3.fromDegrees(
next_point.long,
next_point.lat,
next_point.alt
),
Cesium.Cartesian3.fromDegrees(
prev_point.long,
prev_point.lat,
prev_point.alt
)
);
items.push({
id: prev_point.id,
changes: { dist: new_prev_point_dist },
});
new_sum_dist =
path.sumdist - point.dist - prev_point.dist + new_prev_point_dist;
break;
}
if (items.length > 0) {
debugger;
// dispatch(pathUpdateOne({ id: path_id, changes: { wps: wps } }));
dispatch(pointUpdateAll(items));
// TODO: should find another approach to update path after delete
dispatch(
pathUpdateOne({
id: path_id,
// changes: { wps: wps, sumdist: new_sum_dist },
changes: { wps: wps, sumdist: new_sum_dist },
})
);
dispatch(pointRemove(point_id));
// dispatch(pointUpdateAll(items));
//
}
}
};
return (
<div>
<Entity
// show={point.is_user_made}
selected={point.is_focused}
id={"path_" + point.path_id + "point_" + point_id}
name={"path_" + point.path_id + "point_" + point_id}
description={"path_" + point.path_id + "point_" + point_id}
position={Cesium.Cartesian3.fromDegrees(
parseFloat(point["long"]),
parseFloat(point["lat"]),
parseFloat(point["alt"])
)}
onClick={() => handleOnClick(point_id)}
onRightClick={(e) =>
window.confirm("آیا از حذف این نقطه مطمین هستید؟") &&
handleOnRClick(point.path_id, point_id)
}
>
<PointGraphics
// show={point.is_user_made}
color={DrawSetting["path_point_Color"]}
pixelSize={DrawSetting["path_point_size"]}
outlineColor={DrawSetting["path_point_outlineColor"]}
outlineWidth={DrawSetting["path_point_outlineWidth"]}
/>
</Entity>
</div>
);
}
export default PointItem;
不知道够不够。
解决方案
这里有很多东西要解压。虽然我不确定它是否能解决您的问题,但我想提供一些反馈。
通常,新状态的计算不应该发生在您的组件中,而应该发生在您的 reducer 中。(Redux 风格指南:Put as Much Logic as possible in Reducers)您通常也不应该分派多个(避免顺序分派许多动作)“setter 风格”分派调用,而应该只分派一个“事件类型”分派调用。(将动作建模为事件,而不是设置器)。连续分派 3 次可能会导致组件重新渲染 3 次,中间会出现意想不到的状态组合。
这将从该组件中移出大量代码,使其更具可读性,并可能使查找错误源变得更加明显(如果与在不一致状态下渲染有关,甚至可以消除它)
推荐阅读
- python - 熊猫申请排
- android - 如何修复无法解决:support-compat
- interrupt - 8051 中断(硬件)能力
- c# - 如何在发布到网络位置时在启动时自动更新 .net 应用程序
- c# - Xceed Docx 表格单元格中的段落间距错误
- angular5 - 当我安装 angular2-image-gallery 包时,它会在节点模块的文件导入 rxjs/internal/Subscription 中引发错误
- java - url html表单在webview android中打开
- r - 在模型公式中引用许多匹配正则表达式的列的简洁方法
- deep-learning - 语义分割中的条件随机场
- r - 在R中的循环之前将NA分配给新列