reactjs - 无法覆盖 Typescript 中的局部变量
问题描述
我正在尝试使用从 Typescript 中的函数调用返回的动态项目列表创建一个下拉列表,但我无法覆盖代码中定义的变量并不断获取它们的初始值作为返回。
我设法读取函数返回的下拉项的值,但无法将这些值分配给下拉项参数。这是我的代码:
let tempList: myObject[] = []; //unable to overwrite
const myComponent = () => {
let dropdownItems=[{label: ""}]; //unable to overwrite
fetchAllDropdownItems().then((x)=> tempList = x).catch((err)=> console.log(err))
//Converting myObject array to a neutral array
myList.forEach((y)=> dropdownItems.push(y))
console.log(tempList) // returns [{label: "A"}, {label: "B"}]
console.log(dropdownItems)// returns [{label: ""}, {label: "A"}, {label: "B"}]
return (
<GridContainer>
<GridItem>
<Dropdown
items={dropdownItems} // results in initial value of dropdownItems i.e {label: ""}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
这是 myObject 的样子:
export interface myObject {
label: string;
}
以前我在下拉列表中定义了项目,items={[{ label: "A" }, {label: "B"}]}
它与我从 -function return 获得的结构基本相同,fetchAllDropdownItems
但我的目标是不对项目进行硬编码。
我需要帮助来弄清楚为什么我无法覆盖变量,并希望得到任何建议/建议。提前致谢。
解决方案
问题不在于您没有更新tempList
,而是您的组件在您执行之前渲染并且没有告诉它重新渲染,因为您没有使用该列表作为状态。
使用您显示的代码结构,您有两个选择:
让你的整个模块等到你从服务器获取列表之前,甚至在导出你的组件之前,通过使用顶级
await
(第 3 阶段提案很好地进入第 4 阶段 [“完成”],在现代 bunders 中得到了很好的支持)或者
收到列表后让您的组件重新渲染
这是#1的示例:
const dropdownItems: myObject[] = await fetchAllDropdownItems();
// top-level await −−−−−−−−−−−−−−−^
const myComponent = () => {
return (
<GridContainer>
<GridItem>
<Dropdown
items={dropdownItems}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
再次注意,它加载项目一次然后重用它们,在加载此模块时加载它们。这意味着即使您的组件从未实际使用过,它也可能会加载项目。
有很多不同的方法可以旋转 #2。
这是其中之一:
const dropdownItems: Promise<myObject[]> = fetchAllDropdownItems();
const myComponent = () => {
const [items, setItems] = useState<myObject[] | null>(null);
useEffect(() => {
let unmounted = false;
dropdownItems
.then(items => {
if (!unmounted) {
setItems(items);
}
})
.catch(error => {
// ...handle/display error loading items...
});
return () => {
unmounted = true;
};
}, []);
return (
<GridContainer>
<GridItem>
<Dropdown
items={items || []}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
一旦你的模块被加载,它就会主动加载项目,所以就像#1一样,即使你的组件从未使用过,它也会加载它们,但这意味着项目(可能)在那里并准备好在你的组件第一次使用时使用用过的。
但是最后一段中的“可能”只是:在使用您的组件之前,获取可能仍然未解决。这就是组件使用 Promise 的原因。这意味着在该示例中,您的组件将始终呈现两次:一次为空白,然后再次与列表一起呈现。它会相当快,但它会是两倍。如果项目已经加载,则只发生一次是可能的,但会使代码明显复杂化:
let dropdownItems: myObject[] | null = null;
const dropdownItemsPromise: Promise<myObject[]>
= fetchAllDropdownItems().then(items => {
dropdownItems = items;
return items;
})
.catch(error => {
// ...handle/display error loading items...
});
const myComponent = () => {
const [items, setItems] = useState<myObject[] | null>(dropdownItems);
useEffect(() => {
let unmounted = false;
if (items === null) {
dropdownItemsPromise.then(items => {
if (!unmounted) {
setItems(items);
}
});
}
return () => {
unmounted = true;
};
}, [items]);
return (
<GridContainer>
<GridItem>
<Dropdown
items={items || []}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
或者您可能希望等到第一次使用组件后才加载项目:
let dropdownItems: myObject[] | null = null;
const myComponent = () => {
const [items, setItems] = useState<myObject[] | null>(dropdownItems);
useEffect(() => {
let unmounted = false;
if (items === null) {
fetchAllDropdownItems().then(items => {
dropdownItems = items;
if (!unmounted) {
setItems(items);
}
})
.catch(error => {
if (!unmounted) {
// ...handle/display error loading items...
}
});
}
return () => {
unmounted = true;
};
}, [items]);
return (
<GridContainer>
<GridItem>
<Dropdown
items={items || []}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
或者您可能希望在每次使用组件时加载项目(可能它们会随着时间而改变,或者组件很少使用并且似乎没有必要在代码中缓存它们):
const myComponent = () => {
const [items, setItems] = useState<myObject[] | null>(dropdownItems);
useEffect(() => {
let unmounted = false;
fetchAllDropdownItems().then(items => {
if (!unmounted) {
setItems(items);
}
})
.catch(error => {
if (!unmounted) {
// ...handle/display error loading items...
}
});
return () => {
unmounted = true;
};
}, [items]);
return (
<GridContainer>
<GridItem>
<Dropdown
items={items || []}
onChange={(e) => {
console.log(e?.value)
}}
placeholder="Select an option"
/>
</GridItem>
</GridContainer>
);
};
export default myComponent;
推荐阅读
- java - 无法通过 KAFKA api 连接到 EventHub
- javascript - 完成工作前的 javascript 函数日志记录
- mongodb - 如何使用 findone 从 Mongodb 集合中返回一个数组
- c - 双参考循环变量在循环更新时发生变化
- javascript - 当我让用户通过firebase注册时,他进行了身份验证,但数据没有写入firebase db?
- java - 如何在 mockito 中模拟 Class.forName()
- vue.js - 访问子组件数据时出现问题
- json - 空手道配置文件中写入的用户名/密码在功能文件中的 Post 请求中不起作用
- angular - 根据时区更改 mat-datepicker 选择的日期值
- java - 使用 --debug 运行 spring 应用程序不会影响我的记录器