React Store 第一次没有 return getMethod 的值
React Store does not return getMethod's value first time
我是 React、Mobx 堆栈的新手。我遇到了一个问题,我的商店在第一次调用后没有立即反映它的价值。当我进行第二次调用时,它 returns 第一个值。我无法理解为什么会发生这种情况,因为我在 React、Mobx 堆栈方面还有很长的路要走。
我的商店Class
export default class ServiceTemplateStore {
loadingInitial = false;
serviceTemplateDetail: any | undefined;
constructor() {
makeAutoObservable(this)
}
setLoadingInitial = (state: boolean) => {
this.loadingInitial = state;
}
get getServiceTemplateDetail() {
return this.serviceTemplateDetail;
}
loadServiceTemplateDetail = async (id: string) => {
this.loadingInitial = true;
try {
const serviceTemplateDetail = await agent.serviceTemplateDetail.details(id);
runInAction(() => {
console.log("Service loaded");
this.serviceTemplateDetail = serviceTemplateDetail;
console.log(this.serviceTemplateDetail); //Here I can see it immediately outputs the value.
this.setLoadingInitial(false);
});
} catch (error) {
console.log(error);
this.setLoadingInitial(false);
}
}
}
子组件
这是我使用商店的地方,当我使用 useEffect
挂钩时它实际上填充了数据,但是当我 运行 在 onClick
函数内部时它不填充值。
我的理解是 Axios GET
调用按预期执行,它 returns 返回值并将其分配给 serviceTemplateDetail
变量。但是当我通过 getServiceTemplateDetail
方法访问该值时,它是第一次 returns null,当我下次单击“导入”按钮时,它 returns 从 [= 返回的旧值15=]请求
import DataGrid, { Selection } from "devextreme-react/data-grid";
import Popup, { Position, ToolbarItem } from "devextreme-react/popup";
import { Column } from "devextreme-react/tree-list";
import { observer } from "mobx-react-lite";
import React, { Component, useCallback, useEffect, useState } from 'react'
import { useStore } from "../store/Store";
export default observer(function ImportServiceTemplate(props: importServiceProp) {
const [ serviceTemplateIds, setServiceTemplateIds] = useState([]);
const { serviceTemplateStore } = useStore();
const { serviceTemplateList, loadServiceTemplateList, loadServiceTemplateDetail, getServiceTemplateDetail, serviceTemplateDetail } = serviceTemplateStore;
useEffect(() => {
if (serviceTemplateList?.length === 0 || serviceTemplateList === undefined) loadServiceTemplateList();
}, [loadServiceTemplateList])
const closeButtonOption = {
icon: 'close',
text: 'Close',
onClick: ()=>{
props.onCloseImportModel();
}
};
//Added a useEffect to test..
//UseEffect returns the value but not my Import function below
useEffect(() => {
console.log("use effect");
console.log(JSON.stringify(getServiceTemplateDetail));
}, [getServiceTemplateDetail])
//Actual function that needs to work.
const importButtonOption = {
icon: 'download',
text: 'Import',
onClick: () => {
if(serviceTemplateIds){
loadServiceTemplateDetail(String(serviceTemplateIds))
.then(()=>{
console.log("Callback");
console.log(JSON.stringify(serviceTemplateDetail)); // Getting undefined as output.
props.importingServiceTemplate(getServiceTemplateDetail); //Passing the imported value to parent component
});
}
}
};
const onSelectionChanged = (e: any) => {
console.log("Processing", e.selectedRowKeys);
setServiceTemplateIds(e.selectedRowKeys);
};
return (
<>
<Popup
visible={props.isImportVisible}
dragEnabled={false}
closeOnOutsideClick={false}
showCloseButton={false}
showTitle={true}
title="Service Template"
width={800}
height={280}>
<Position
at="center"
my="center"
/>
<DataGrid
id="serviceTemplateGrid"
key="ServiceTemplateId"
keyExpr="ServiceTemplateId"
focusedRowEnabled={true}
onSelectionChanged={onSelectionChanged}
selectedRowKeys={serviceTemplateIds}
dataSource={serviceTemplateList}
showRowLines={true}
showBorders={true}>
<Selection mode="multiple" showCheckBoxesMode="onClick" />
<Column dataField="Name" caption="Name" />
<Column dataField="CustomerName" caption="Customer Name" />
<Column dataField="BaseCurrencyCode" caption="Currency" />
<Column dataField="Description" caption="Description" />
</DataGrid>
<ToolbarItem
widget="dxButton"
toolbar="bottom"
location="before"
options={closeButtonOption}
/>
<ToolbarItem
widget="dxButton"
toolbar="bottom"
location="after"
options={importButtonOption}
/>
<div>{JSON.stringify(getServiceTemplateDetail)}</div>
</Popup>
</>
)
})
interface importServiceProp{
isImportVisible: boolean;
onCloseImportModel: Function
importingServiceTemplate: any
}
这不是 React 或 MobX 的问题,只是一个常规的 javascript 闭包。
当您创建 importButtonOption
函数时,它 remembers
它周围的所有变量,并且 serviceTemplateDetail
第一次等于未定义。因此,在您调用 loadServiceTemplateDetail
后,serviceTemplateDetail
在商店中发生了更改,但在 importButtonOption
函数内部它仍然是一个旧值,在创建函数时是 remembered
。
希望它有意义。基本上你只需要阅读闭包及其工作原理。
里面有个小攻略
例如,您可以做的是删除值的解构并根据需要取消引用它们,就像这样:
loadServiceTemplateDetail(String(serviceTemplateIds))
.then(()=>{
console.log("Callback");
console.log(JSON.stringify(serviceTemplateStore .serviceTemplateDetail)); // reference it from the store to get actual value
props.importingServiceTemplate(getServiceTemplateDetail); //Passing the imported value to parent component
});
我是 React、Mobx 堆栈的新手。我遇到了一个问题,我的商店在第一次调用后没有立即反映它的价值。当我进行第二次调用时,它 returns 第一个值。我无法理解为什么会发生这种情况,因为我在 React、Mobx 堆栈方面还有很长的路要走。
我的商店Class
export default class ServiceTemplateStore {
loadingInitial = false;
serviceTemplateDetail: any | undefined;
constructor() {
makeAutoObservable(this)
}
setLoadingInitial = (state: boolean) => {
this.loadingInitial = state;
}
get getServiceTemplateDetail() {
return this.serviceTemplateDetail;
}
loadServiceTemplateDetail = async (id: string) => {
this.loadingInitial = true;
try {
const serviceTemplateDetail = await agent.serviceTemplateDetail.details(id);
runInAction(() => {
console.log("Service loaded");
this.serviceTemplateDetail = serviceTemplateDetail;
console.log(this.serviceTemplateDetail); //Here I can see it immediately outputs the value.
this.setLoadingInitial(false);
});
} catch (error) {
console.log(error);
this.setLoadingInitial(false);
}
}
}
子组件
这是我使用商店的地方,当我使用 useEffect
挂钩时它实际上填充了数据,但是当我 运行 在 onClick
函数内部时它不填充值。
我的理解是 Axios GET
调用按预期执行,它 returns 返回值并将其分配给 serviceTemplateDetail
变量。但是当我通过 getServiceTemplateDetail
方法访问该值时,它是第一次 returns null,当我下次单击“导入”按钮时,它 returns 从 [= 返回的旧值15=]请求
import DataGrid, { Selection } from "devextreme-react/data-grid";
import Popup, { Position, ToolbarItem } from "devextreme-react/popup";
import { Column } from "devextreme-react/tree-list";
import { observer } from "mobx-react-lite";
import React, { Component, useCallback, useEffect, useState } from 'react'
import { useStore } from "../store/Store";
export default observer(function ImportServiceTemplate(props: importServiceProp) {
const [ serviceTemplateIds, setServiceTemplateIds] = useState([]);
const { serviceTemplateStore } = useStore();
const { serviceTemplateList, loadServiceTemplateList, loadServiceTemplateDetail, getServiceTemplateDetail, serviceTemplateDetail } = serviceTemplateStore;
useEffect(() => {
if (serviceTemplateList?.length === 0 || serviceTemplateList === undefined) loadServiceTemplateList();
}, [loadServiceTemplateList])
const closeButtonOption = {
icon: 'close',
text: 'Close',
onClick: ()=>{
props.onCloseImportModel();
}
};
//Added a useEffect to test..
//UseEffect returns the value but not my Import function below
useEffect(() => {
console.log("use effect");
console.log(JSON.stringify(getServiceTemplateDetail));
}, [getServiceTemplateDetail])
//Actual function that needs to work.
const importButtonOption = {
icon: 'download',
text: 'Import',
onClick: () => {
if(serviceTemplateIds){
loadServiceTemplateDetail(String(serviceTemplateIds))
.then(()=>{
console.log("Callback");
console.log(JSON.stringify(serviceTemplateDetail)); // Getting undefined as output.
props.importingServiceTemplate(getServiceTemplateDetail); //Passing the imported value to parent component
});
}
}
};
const onSelectionChanged = (e: any) => {
console.log("Processing", e.selectedRowKeys);
setServiceTemplateIds(e.selectedRowKeys);
};
return (
<>
<Popup
visible={props.isImportVisible}
dragEnabled={false}
closeOnOutsideClick={false}
showCloseButton={false}
showTitle={true}
title="Service Template"
width={800}
height={280}>
<Position
at="center"
my="center"
/>
<DataGrid
id="serviceTemplateGrid"
key="ServiceTemplateId"
keyExpr="ServiceTemplateId"
focusedRowEnabled={true}
onSelectionChanged={onSelectionChanged}
selectedRowKeys={serviceTemplateIds}
dataSource={serviceTemplateList}
showRowLines={true}
showBorders={true}>
<Selection mode="multiple" showCheckBoxesMode="onClick" />
<Column dataField="Name" caption="Name" />
<Column dataField="CustomerName" caption="Customer Name" />
<Column dataField="BaseCurrencyCode" caption="Currency" />
<Column dataField="Description" caption="Description" />
</DataGrid>
<ToolbarItem
widget="dxButton"
toolbar="bottom"
location="before"
options={closeButtonOption}
/>
<ToolbarItem
widget="dxButton"
toolbar="bottom"
location="after"
options={importButtonOption}
/>
<div>{JSON.stringify(getServiceTemplateDetail)}</div>
</Popup>
</>
)
})
interface importServiceProp{
isImportVisible: boolean;
onCloseImportModel: Function
importingServiceTemplate: any
}
这不是 React 或 MobX 的问题,只是一个常规的 javascript 闭包。
当您创建 importButtonOption
函数时,它 remembers
它周围的所有变量,并且 serviceTemplateDetail
第一次等于未定义。因此,在您调用 loadServiceTemplateDetail
后,serviceTemplateDetail
在商店中发生了更改,但在 importButtonOption
函数内部它仍然是一个旧值,在创建函数时是 remembered
。
希望它有意义。基本上你只需要阅读闭包及其工作原理。
里面有个小攻略例如,您可以做的是删除值的解构并根据需要取消引用它们,就像这样:
loadServiceTemplateDetail(String(serviceTemplateIds))
.then(()=>{
console.log("Callback");
console.log(JSON.stringify(serviceTemplateStore .serviceTemplateDetail)); // reference it from the store to get actual value
props.importingServiceTemplate(getServiceTemplateDetail); //Passing the imported value to parent component
});