我在尝试理解React/Redux的一些行为时遇到了一些困难。我有一个带有选项卡式界面的网页。每个选项卡式页面都包含几个子组件--例如一个搜索字段和一些顶级选项,然后使用这些子组件从服务器获取数据并将其显示在下面的表中。我使用AG-Grid作为表,一些单元格也包含单独呈现的组件。
在这种情况下,会发生以下情况:
1.我加载选项卡页
1.选项卡页使用空redux-store变量初始化-表中没有信息,搜索字段中也没有要显示的内容
1.用户从搜索框列表中选择一项
1.现在,redux-store状态将根据所选搜索使用获取的服务器数据进行更新
1.该状态应该保留在页面上。现在,如果我从表中调用函数(双击函数),该状态显示的是初始化值,而不是当前的存储值。但是,如果我在尝试运行表函数之前在页面上执行 * 任何其他操作 *,则redux-store值将被调用,代码将按预期运行。
下面是一些代码片段,因为代码太长,无法在这里重现。
这是从主页加载的初始选项卡页:
const BuildProjectView = (props: {inputProjectObj: any}): JSX.Element => {
const dispatch = useDispatch();
const [selectedProject, setSelectedProject] = useState<Project>(projectEmptyObj);
// fetch static data (once)
useEffect(() => {
//...fetch the background data required to display the page
}, []);
return(
<React.Fragment>
<BuildView inputProjectData={selectedProject}/>
<BuildProjectTableView />
</React.Fragment>
);
}
在这个例子中,selectedProject
中没有要呈现的内容,我传入初始化状态。下面是BuildView代码:
const BuildView:React.FC<{inputProjectData: Project}> = (props) => {
return (
<Row>
<Col xl={6} lg={6}>
<ProjectSearchForm inputProjectData={props.inputProjectData}/>
</Col>
<Col xl={6} lg={6}>
<FicMaterialSearchForm />
</Col>
</Row>
);
}
现在,这里是ProjectSearchForm,redux存储在这里填充页面的其余部分:
const ProjectSearchForm = (props: {inputProjectData: Project}): JSX.Element => {
const dispatch = useDispatch();
//lots of other page state controllers here
const projectData: Project = useSelector((state: RootState) => state.buildview.selectedProject);
const selectedBuild: Build = useSelector((state: RootState) => state.buildview.selectedBuild);
const [selectedProject, setSelectedProject] = useState(projectEmptyObj);
<...>
const projectChangeHandler = (event: any, value: Project | null): void => {
if (value !== null) {
dispatch(buildViewActions.setEditOption({editOption: false}));
const projectId: number = value?.engagement;
setSelectedProject(value);
// determine project builds
dispatch(getProjectBuildData(projectId));
}
}
return (
<React.Fragment>
<Form>
<Form.Group as={Row} controlId="projectSearchField">
<Form.Label column xl={1} lg={1} className="mr-1">Project:</Form.Label>
<Col xl={7} lg={7}>
<Autocomplete
<...Autocomplete field options here...>
onChange={projectChangeHandler}
value={selectedProject}
/>
</Col>
</Form.Group>
</Form>
</React.Fragment>
现在,我的Redux存储变量state.buildview.selectedProject
已经更新。现在,我对上面呈现为空表的ProjectBuildTableView
感兴趣。BuildProjectTableView
包含许多表函数,这些函数由填充表的各种存储跟踪,以及表中呈现的组件。
const ProjectBuildTableView = (): JSX.Element => {
//here I'm bringing in the Redux store component that is updated from the other view
const projectData: Project = useSelector((state: RootState) => state.buildview.selectedProject);
const selectedBuild: Build = useSelector((state: RootState) => state.buildview.selectedBuild);
const openNewTabWhenCellDbClicked = (data: BuildItem | SerialItem, type: string): void => {
const tabRequest = {
tabId: type,
tabChangeTrigger: true,
inputObj: {
data: data,
//EMPTY projectData!!
projectData: projectData,
selectedBuild: selectedBuild,
from: 'build'
}
}
dispatch(commonActions.updateTabOptions({tabRequest: tabRequest}));
}
第一次加载页面后,我从搜索字段中选择了一些内容,并验证了数据已加载到存储中,我尝试双击表中的一个单元格,projectData
和selectedBuild
被设置为它们的初始化值(它们不是未定义的,也不是空值,它们具有来自存储示例化的初始化接口值)。
如果我与ProjectSearchForm
组件上的 * 任何其他元素 * 进行交互,即使我的交互没有触及存储,存储也会保留其值!我可以双击或在页面中执行任何其他导航,projectData
会保持其状态。
我不知道这个问题的原因,如果我没有提供足够的信息来确定原因,我很抱歉。我已经设置了断点和useEffects来跟踪组件中projectData状态的更改,* 直到 * 我在更改存储区后首次与页面交互时,才有任何值更改的迹象。
提前感谢您的任何见解!
编辑:我还想指出的是,在调试模式下,store中的状态似乎没有变化。我正在Chrome中检查Redux调试器,值被正确存储。只有在本地第一页交互中,store变量(来自useSelector)是不正确的。
1条答案
按热度按时间irtuqstp1#
我发现了这个问题。我可能(仍然)对底层函数指针和状态传递时的内存处理缺乏一些了解。本质上,似乎发生了什么:
1.我将顶级函数向下传递给较低级别的组件
1.较低级别的函数未更新,即使跟踪了存储值
1.已从较低级别调用该函数,但仍包含过时的状态值
解决方案:强制较低级别的函数重新呈现;* 在 * 状态值更新后重新发送更新的函数指针(通过useEffect强制渲染)
我希望其他人会发现这很有用,并意识到React缓存了整个函数,而不是通过引用传递它们。