2022 React 最速上手指南(十三)—— 内联处理函数 & 异步数据 & 条件渲染

简介: 2022 React 最速上手指南(十三)—— 内联处理函数 & 异步数据 & 条件渲染

以结果为导向,写给刚学完前端三剑客和想要了解 React 框架的小伙伴,使得他们能快速上手(省略了历史以及一些不必要的介绍)。



JSX 内联处理函数


到目前为止,我们拥有的 stories 列表只是一个无状态的变量,可以通过搜索来过滤渲染的列表,但是列表本身保持不变。


如果我们想要加一个【从列表中删除项目】的功能,就要取得列表的控制权,我们可以把列表作为 useState hook 的初始 state(之所以不使用我们自定义的 hook,是因为我们不想每次打开浏览器显示的都是缓存列表),然后向下传递一个回调处理函数。


const initialStories = [
  ...
];
...
const App = () => {
  ...
  const [stories, setStories] = React.useState(initialStories);
  const handleRemoveStory = (item) => {
    const newStories = stories.filter(
      (story) => item.objectID !== story.objectID
    );
    setStories(newStories);
  };
  ...
  return (
    <>
      <InputWithLabel
        id="search"
        value={searchTerm}
        onInputChange={handleSearch}
        isFocused
      >
        <strong>Search:</strong>
      </InputWithLabel>
      <hr />
      <List list={searchedStories} onRemoveItem={handleRemoveStory} />
    </>
  );
};
复制代码


回调函数接收要删除的 item,然后将返回的 newStories 设置为新的 state。

List 组件会向下传递这个函数给它的子组件:


const List = ({ list, onRemoveItem }) =>
  list.map((item) => (
    <Item key={item.objectID} item={item} onRemoveItem={onRemoveItem} />
  ));
const Item = ({ item, onRemoveItem }) => (
  <div>
    <span>
      <a href={item.url}>{item.title}</a>
    </span>
    <span>{item.author}</span>
    <span>
      <button onClick={() => onRemoveItem(item)}>Dismiss</button>
    </span>
  </div>
);
复制代码


使用【内联处理函数】,在点击按钮时调用 App 组件里的 onRemoveItem() 触发删除事件。


它与常规的处理函数类似,只是函数体放在了 JSX 中,但由于 JS 逻辑隐藏在 JSX 中,可能会导致代码难以调试,所以在【实现逻辑冗长】时,我们应该避免使用内联处理函数,而是直接采用常规方式,就像这样:


const Item = ({ item, onRemoveItem }) => {
  const handleRemoveItem = () => {
    onRemoveItem(item);
  };
  return (
    <div>
      <span>
        <a href={item.url}>{item.title}</a>
      </span>
      <span>{item.author}</span>
      <span>
        <button onClick={handleRemoveItem}>Dismiss</button>
      </span>
    </div>
  );
};
复制代码


异步数据 & 条件渲染


在真实应用中,我们一般先要渲染出一个组件,然后再请求第三方 API 得到数据并将其显示在组件上。


我们使用一个空数组作为初始的 state,然后通过一个简单的 promise 函数加上一点延迟来【模拟异步获取数据的过程】:


const getAsyncStories = () =>
  new Promise((resolve) =>
    setTimeout(() => resolve({ data: { stories: initialStories } }), 2000)
  );
const App = () => {
  ...
  const [stories, setStories] = React.useState([]);
  React.useEffect(() => {
    getAsyncStories().then((res) => {
      setStories(res.data.stories);
    });
  }, []);
  ...
};
复制代码


由于 useEffect 的依赖数组是【空数组】,因此副作用函数仅在组件首次渲染后执行,函数在解析完 promise 并修改 state 后,组件会再次渲染并显示异步加载的数据。

关于 promise 的用法这里写一个示例,查看文档阅读更多。


const makeServerRequest = new Promise((resolve, reject) => {
  // 做一些异步操作,假设从远端API调取数据
  // 成功拿到数据调用resolve(),失败调用reject()
  if(responseFromServer) {
    resolve("We got the data");
  } else {  
    reject("Data not received");
  }
});
// resolve()执行时调用
makeServerRequest.then(result => {
  console.log(result); // "We got the data"
});
// reject()执行时调用
makeServerRequest.catch(error => {
  console.log(error); // "Data not received"
});
复制代码


处理异步数据使我们处于有数据和无数据这两种【条件状态】,我们需要在数据加载时为用户显示一个加载指示器:


const [isLoading, setIsLoading] = React.useState(false);
React.useEffect(() => {
  setIsLoading(true);
  getAsyncStories().then((res) => {
    setStories(res.data.stories);
    setIsLoading(false);
  });
}, []);
复制代码


通过三元运算符在 JSX 中内联条件渲染,当 isLoading 条件为 true,显示一个提示标签:


const App = () => {
  ...
  return (
    <>
      ...
      <hr />
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <List list={searchedStories} onRemoveItem={handleRemoveStory} />
      )}
    </>
  );
};
复制代码


真实应用中调用第三方 API 的数据很有可能会出错,我们引入另一个 state,然后使用 Promise.catch() 来处理错误状态:


const App = () => {
  const [searchTerm, setSearchTerm] = useSemiPersistentState(
    "search", "React"
  );
  const [stories, setStories] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(false);
  const [isError, setIsError] = React.useState(false);
  React.useEffect(() => {
    setIsLoading(true);
    getAsyncStories()
      .then((res) => {
        setStories(res.data.stories);
        setIsLoading(false);
      })
      .catch(() => setIsError(true));
  }, []);
   ...
};
复制代码


然后使用逻辑与(&&) 运算符,条件渲染一些内容为用户提供反馈:


const App = () => {
  ...
  return (
    <>
      ...
      <hr />
      {isError && <p>Something went wrong ...</p>}
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <List list={searchedStories} onRemoveItem={handleRemoveStory} />
      )}
    </>
  );
};
复制代码


在 React 中,我们经常使用 条件 && JSX 的方式来避免返回 null 值,当左侧条件成立则渲染右侧内容,反之跳过右侧内容。

目录
相关文章
|
2月前
|
前端开发 开发者
React 函数组件与类组件对比
【10月更文挑战第4天】本文详细比较了React中的函数组件与类组件。函数组件是一种简单的组件形式,以纯函数的形式返回JSX,易于理解与维护,适用于简单的UI逻辑。类组件则是基于ES6类实现的,需要重写`render`方法并能利用更多生命周期方法进行状态管理。文章通过示例代码展示了两者在状态管理与生命周期管理上的差异,并讨论了常见的问题如状态更新异步性与生命周期管理的复杂性,最后给出了相应的解决方法。通过学习,开发者可以根据具体需求选择合适的组件类型。
63 8
|
3月前
|
前端开发 JavaScript 区块链
react18函数组件+antd使用指南-使用代码集合以及报错记录汇总
本文介绍了多个React开发中常见的问题及其解决方案,包括但不限于:1)`useForm`实例未连接到任何`Form`元素的警告及解决方法;2)监听页面滚动事件的实现方式;3)React 18与antd 5.8.6中定制主题的方法;4)React结合antd 4.x版本自定义主题色的步骤;5)解决`ResizeObserver loop`相关报错的技巧;6)处理React设计表单时遇到的CDN资源加载失败问题;7)解决onClick事件传参问题;8)修复类型错误等。每部分均提供详细分析与实用代码示例,帮助开发者快速定位并解决问题。
52 2
|
3月前
|
XML JavaScript 前端开发
学习react基础(1)_虚拟dom、diff算法、函数和class创建组件
本文介绍了React的核心概念,包括虚拟DOM、Diff算法以及如何通过函数和类创建React组件。
33 3
|
3月前
|
前端开发
react学习(22)高阶函数和函数柯里化
react学习(22)高阶函数和函数柯里化
|
4月前
|
资源调度 前端开发 API
React Suspense与Concurrent Mode:异步渲染的未来
React的Suspense与Concurrent Mode是16.8版后引入的功能,旨在改善用户体验与性能。Suspense组件作为异步边界,允许子组件在数据加载完成前显示占位符,结合React.lazy实现懒加载,优化资源调度。Concurrent Mode则通过并发渲染与智能调度提升应用响应性,支持时间分片和优先级调度,确保即使处理复杂任务时UI仍流畅。二者结合使用,能显著提高应用效率与交互体验,尤其适用于数据驱动的应用场景。
73 20
|
4月前
|
前端开发
如何编写React函数组件
【8月更文挑战第17天】如何编写React函数组件
23 2
|
4月前
|
存储 前端开发 JavaScript
处理 React 应用程序中的异步数据加载
【8月更文挑战第31天】
66 0
|
4月前
|
前端开发 JavaScript
React 中的函数组件和类组件
【8月更文挑战第31天】
67 0
|
4月前
|
前端开发 JavaScript 开发者
React组件入门秘籍:函数组件、类组件、高阶组件,一文让你彻底解锁!
【8月更文挑战第24天】React是一款广受好评的JavaScript库,其核心特色在于组件化开发模式。React组件作为应用程序的基础单元,不仅能够处理特定业务逻辑还能实现界面展示。本文深入浅出地介绍了React组件的概念、创建方式及其应用场景。
56 0
|
5月前
|
存储 前端开发 安全