蓝冰小站

icy's blog

马上订阅 蓝冰小站 RSS 更新: https://icys.top/atom.xml

从 CallBack 到 Promise,React 框架异步开发学习心得

2023年2月4日 22:00

引入

说起 React,我印象最深刻的是,在 React 中,数据是向下流动的(react 为什么是单向数据流)——越高层级的组件,获得着越多的数据,而低层级组件数据的获取和更新,大多都通过组件属性传递以及回调函数方式得到。这就意味着,高层组件刷新会同时刷新低层组件,而低层组件刷新往往不会带动高层组件刷新,于是更多的状态和逻辑会出现在比较高层级的组件里,在 React 中叫做状态提升 。例如对话框的打开与关闭更应该是对话框组件的属性,而不是对话框组件的状态——对话框的操作往往与高层数据相关,如果把状态放在低层级,则很难把当前的状态和数据与高层级组件交互。

在这种数据流的模式下,为了使得基本组件“动起来”,高层级组件里总会有大大小小的许多状态,以便控制基本组件的开/关、显示/隐藏等等。此外,除了控制基本组件的状态以外,高层级组件本身可能还承担着数据通信的功能,例如我们本次提到的异步请求和发送数据。在 React 中,状态state的更新会使得组件重新进行渲染(见State & 生命周期),有的时候我们只希望重新渲染这个组件的一部分组件(例如刚才所说的对话框),而有的时候我们希望重新请求数据(数据同步、表格翻页)全部刷新,于是我们通常会使用 useEffect 钩子对一些刷新操作添加限定,仅仅在某些变量修改的时候,才会重新执行该部分代码逻辑(在 React 官方文档中叫做关注点分离)。

问题

所以对于一个又需要刷新数据,又需要控制对话框,而且获取数据要请求两次 api 的组件,就会变成这个样子(CallBack 版本):

export default function Component(props) {
let [dialogState, setDialogState] = useState(false); // some states for dialogs
let [renderData, setRenderData] = useState(null); // some states for rendering
let [page, setPage] = useState(1); // some states which force data refresh
useEffect(() => {
fetchSomeData("url", {params: "Some Params"}, {config: "Some Configurations"}, (data) => {
// callback for success
let someProps = getSomeProps(data);
fetchSomeData("url2", {params: someProps}, {config: "Some Configurations"}, (data) => {
// funciton for process
setRenderData(processing(data));
}, () => {});
}, (error) => {
// callback for failure
});
}, [page]); // fetch data only when page changes
if (renderData === null) return null;
return (
<> {/* equals to <React.Fragment> */}
<Dialog someStates={dialogState}/>
<Others...

剩余内容已隐藏

查看完整文章以阅读更多