setState 未在页面加载前从 api 设置初始值
setState not setting initial value from api before page load
正在尝试通过调用 API 来设置我的功能模块的初始状态。我阅读了关于 useState 设置初始值和 useEffect 的内容,其中 运行s 在呈现页面时让我的表单页面从 api 获取默认值,并且用户看到预先填写的表单。
现在我的问题是,当我尝试在 return() 中使用表单内的 api 值时,我没有预先填充其中的值。如果我对 useState({"sor_name": "ani"}) 中的值进行硬编码,我就能够获取表单中的值。为了便于阅读,我缩短了代码。这是我的代码:
const UpdateSOR = (props) => {
const [SOR, setSOR] = useState([]); // Initialized SOR
async function getSOR() {
const res = await QueryService.getSOR(2).then(
res => {
if (res.status === 200) {
setSOR(res.data.data.dataItems[0]); // I get the values in the form {"data":{"dataItems":[{"SOR_NAME":"ani"}]}}
}
}
).catch(error => {
console.log(error);
})
}
useEffect(() => {
getSOR(); // called SOR
}, []);
return (
<form className={`${classes.form} ${classes.body}`} noValidate autoComplete="off">
<Row>
<Col lg="2" onChange = {(event) => setSelectedSorName(event.target.value)}>
<CommonInput
id="sor_name"
label="SOR Name"
defaultValue={SOR.SOR_NAME} // i dont get the value here on initial load.
disabled={false}
multiline={false}
rows="1" />
</Col>
</Row>
</form>
)
注:这是我的功能模块树结构:
app-->appBar(组件)-->SOR(模块)--> updateSOR(模块)
如果用户像这样直接访问 updateSOR (localhost:3000/edit/updateSOR/2),我想 运行 api 并获取值并填写表格并呈现到用户直接。我知道我可以直接从上一页 SOR 将 api 值推送到 props,但这样做只有在用户从 SOR 进入页面时才有效,但如果用户直接输入最后是 id 的页面名称,我需要填充那个 updateSOR 页面。
这是我在 QueryService 中编写的获取数据的函数,我在 useEffect 挂钩中调用这个 updateSOR 组件来获取数据:
function getSOR(id) {
if(id) {
return axios.get(`${Constants.API_URL}/SOR?id=${id}`);
} else {
return axios.get(`${Constants.API_URL}/SOR`);
}
}
这是我的 CommonInput 函数。
export default function CommonInput(props) {
const classes = useStyles();
const { id , label, defaultValue, disabled, multiline, rows } = props;
return (
<FormControl className={classes.formControl}>
<InputLabel id={id}>{label}</InputLabel>
<Input
defaultValue={defaultValue}
id={id}
disabled={disabled}
multiline={multiline}
rows={rows}
/>
</FormControl>
)
}
为了理解这个问题,你需要先理解useEffect
是如何工作的。根据 React Hooks API Reference:
The function passed to useEffect will run after the render is committed to the screen.
您在 useEffect
中为获取数据而进行的异步调用将在 在 您的组件首次呈现后执行。因此,您的组件以初始状态呈现,即为空。网络调用完成后,将调用 setSOR
,触发新状态的重新渲染。
一个解决方案是在 return 之前为未解决的状态提供 return 条件。如果您不想呈现任何内容或某种加载指示器,这可以简单地 return false
。
示例:(我省略了您的一些代码以突出概念)
function UpdateSOR() {
const [SOR, setSOR] = useState(); // default to undefined state.
useEffect(() => {
QueryService.getSOR(2).then(res => {
if (res.status === 200) {
setSOR(res.data.data.dataItems[0]);
}
});
}, []);
if (!SOR) return false; // Render nothing, <p>Loading...</p>, etc.
return <p>{SOR.SOR_NAME}</p>
}
正在尝试通过调用 API 来设置我的功能模块的初始状态。我阅读了关于 useState 设置初始值和 useEffect 的内容,其中 运行s 在呈现页面时让我的表单页面从 api 获取默认值,并且用户看到预先填写的表单。
现在我的问题是,当我尝试在 return() 中使用表单内的 api 值时,我没有预先填充其中的值。如果我对 useState({"sor_name": "ani"}) 中的值进行硬编码,我就能够获取表单中的值。为了便于阅读,我缩短了代码。这是我的代码:
const UpdateSOR = (props) => {
const [SOR, setSOR] = useState([]); // Initialized SOR
async function getSOR() {
const res = await QueryService.getSOR(2).then(
res => {
if (res.status === 200) {
setSOR(res.data.data.dataItems[0]); // I get the values in the form {"data":{"dataItems":[{"SOR_NAME":"ani"}]}}
}
}
).catch(error => {
console.log(error);
})
}
useEffect(() => {
getSOR(); // called SOR
}, []);
return (
<form className={`${classes.form} ${classes.body}`} noValidate autoComplete="off">
<Row>
<Col lg="2" onChange = {(event) => setSelectedSorName(event.target.value)}>
<CommonInput
id="sor_name"
label="SOR Name"
defaultValue={SOR.SOR_NAME} // i dont get the value here on initial load.
disabled={false}
multiline={false}
rows="1" />
</Col>
</Row>
</form>
)
注:这是我的功能模块树结构: app-->appBar(组件)-->SOR(模块)--> updateSOR(模块)
如果用户像这样直接访问 updateSOR (localhost:3000/edit/updateSOR/2),我想 运行 api 并获取值并填写表格并呈现到用户直接。我知道我可以直接从上一页 SOR 将 api 值推送到 props,但这样做只有在用户从 SOR 进入页面时才有效,但如果用户直接输入最后是 id 的页面名称,我需要填充那个 updateSOR 页面。
这是我在 QueryService 中编写的获取数据的函数,我在 useEffect 挂钩中调用这个 updateSOR 组件来获取数据:
function getSOR(id) {
if(id) {
return axios.get(`${Constants.API_URL}/SOR?id=${id}`);
} else {
return axios.get(`${Constants.API_URL}/SOR`);
}
}
这是我的 CommonInput 函数。
export default function CommonInput(props) {
const classes = useStyles();
const { id , label, defaultValue, disabled, multiline, rows } = props;
return (
<FormControl className={classes.formControl}>
<InputLabel id={id}>{label}</InputLabel>
<Input
defaultValue={defaultValue}
id={id}
disabled={disabled}
multiline={multiline}
rows={rows}
/>
</FormControl>
)
}
为了理解这个问题,你需要先理解useEffect
是如何工作的。根据 React Hooks API Reference:
The function passed to useEffect will run after the render is committed to the screen.
您在 useEffect
中为获取数据而进行的异步调用将在 在 您的组件首次呈现后执行。因此,您的组件以初始状态呈现,即为空。网络调用完成后,将调用 setSOR
,触发新状态的重新渲染。
一个解决方案是在 return 之前为未解决的状态提供 return 条件。如果您不想呈现任何内容或某种加载指示器,这可以简单地 return false
。
示例:(我省略了您的一些代码以突出概念)
function UpdateSOR() {
const [SOR, setSOR] = useState(); // default to undefined state.
useEffect(() => {
QueryService.getSOR(2).then(res => {
if (res.status === 200) {
setSOR(res.data.data.dataItems[0]);
}
});
}, []);
if (!SOR) return false; // Render nothing, <p>Loading...</p>, etc.
return <p>{SOR.SOR_NAME}</p>
}