使用hooks写React组件需要注意的5个地方

 更新时间:2021年04月07日 09:57:07   作者:forrest酱  
这篇文章主要介绍了使用hooks写React组件需要注意的5个地方,帮助大家更好的理解和学习使用React组件,感兴趣的朋友可以了解下

Hook是React16.8开始新增的特性。虽然React官方文档已经作出了针对React hooks的相关概念的讲解,但是光看官方文档是很难将hooks使用好的,在编写hooks的过程中很容易跳进陷阱和错误。本文总结了5个不好的地方。

01.不需要render的场景下使用useState

在函数组件中我们可以使用useState来管理状态,这使得对状态的管理变得很简单,但是也容易被滥用,我们通过下面的代码样例看下容易忽略的地方。

不推荐×

function ClickButton(props){
 const [count, setCount] = setState(0)
 const onClickCount = () => {
  setCount((c) => c + 1)
 }
 const onClickRequest = () => {
  apiCall(count)
 }
 
 return (
  <div>
   <button onClick={onClickCount}>Click</button>
   <button onClick={onClickRequest}>Submit</button>
  </div>
 )
}

问题所在:仔细看上面的代码,乍一看其实也没什么问题,点击按钮更新 count。但是问题也就出在这里,我们的 return 部分并没有用到 count 状态,而每次 setCount 都会使组件重新渲染一次,而这个渲染并不是我们需要的,多出来的渲染会使得页面的性能变差,因此我们可以改造一下代码,如下代码:

推荐√
如果我们只是单纯的想要一个能在组件声明周期内保存的变量,但是变量的更新不需要组件的重新渲染,我们可以使用 useRef 钩子。

function ClickButton(props){
 const count = useRef(0)
 const onClickCount = () => {
  count.current++
 }
 const onClickRequest = () => {
  apiCall(count.current)
 }

 return (
  <div>
   <button onClick={onClickCount}>Click</button>
   <button onClick={onClickRequest}>Submit</button>
  </div>
 )
}

02.使用了router.push而非link

在React SPA应用中,我们用react-router来处理路由的跳转,我们很经常在组件中写了一个按钮,通过点击按钮的事件来处理路由的跳转,如下代码:

不推荐×

function ClickButton(props){
 const history = useHistory()
 const onClickGo = () => {
  history.push('/where-page')
 }
 return <button onClick={onClickGo}>Go to where</button>
}

问题所在:尽管上述代码可以正常工作,但是却不符合Accessibility(易访问性设计)的要求,此类按钮并不会被屏幕阅读器当作一个可以跳转的链接。因此我们可以改造一下代码,如下代码:

推荐√

function ClickButton(props){
 return <Link to="/next-page">
  <span>Go to where</span>
 </Link>
}

03.通过useEffect来处理actions

有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。比如发送网络请求,手动变更 DOM,记录日志。

不推荐×

function DataList({ onSuccess }) {
 const [loading, setLoading] = useState(false);
 const [error, setError] = useState(null);
 const [data, setData] = useState(null);

 const fetchData = () => {
  setLoading(true);
  callApi()
   .then((res) => setData(res))
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 useEffect(() => {
  fetchData();
 }, []);

 useEffect(() => {
  if (!loading && !error && data) {
   onSuccess();
  }
 }, [loading, error, data, onSuccess]);

 return <div>Data: {data}</div>;
}

问题所在:上面的代码使用了两个useEffect ,第一个用来请求异步数据,第二个用来调用回调函数。在第一个异步请求数据成功,才会触发第二个 useEffect 的执行,但是,我们并不能完全保证,第二个 useEffect 的依赖项完全受控于第一个 useEffect 的成功请求数据。因此我们可以改造一下代码,如下代码:

推荐√

function DataList({ onSuccess }) {
 const [loading, setLoading] = useState(false);
 const [error, setError] = useState(null);
 const [data, setData] = useState(null);

 const fetchData = () => {
  setLoading(true);
  callApi()
   .then((res) => {
    setData(res)
    onSuccess()
    })
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 useEffect(() => {
  fetchData();
 }, []);
 return <div>Data: {data}</div>;
}

04.单一职责组件

什么时候该把一个组件分成几个更小的组件?如何构建组件树?在使用基于组件的框架时,所有这些问题每天都会出现。然而,设计组件时的一个常见错误是将两个用例组合成一个组件。

不推荐×

function Header({ menuItems }) {
 return (
  <header>
   <HeaderInner menuItems={menuItems} />
  </header>
 );
}

function HeaderInner({ menuItems }) {
 return isMobile() ? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />;
}

问题所在:上面的代码通过这种方法,组件HeaderInner试图同时成为两个不同的东西,一次做不止一件事情并不是很理想。此外,它还使得在其他地方测试或重用组件变得更加困难。因此我们可以改造一下代码,如下代码:

推荐√

将条件提升一级,可以更容易地看到组件的用途,并且它们只有一个职责,即<Tabs/><BurgerButton/>,而不是试图同时成为两个不同的东西。

function Header(props) {
 return (
  <header>
   {isMobile() ? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />}
  </header>
 )
}

05.单一职责useEffects

通过对比componentWillReceivePropscomponentDidUpdate方法,才认识到userEffect的美丽。但是没有妥当使用useEffect也是容易出问题的。

不推荐×

function Example(props) {
 const location = useLocation();
 const fetchData = () => {
  /* Calling the api */
 };

 const updateBreadcrumbs = () => {
  /* Updating the breadcrumbs*/
 };

 useEffect(() => {
  fetchData();
  updateBreadcrumbs();
 }, [location.pathname]);

 return (
  <div>
   <BreadCrumbs />
  </div>
 );
}

问题所在:上面的useEffect同时触发了两个副作用,但是并不都是我们需要的副作用,因此我们可以改造一下代码,如下代码:

推荐√

将两个副作用从一个useEffect中分离出来。

function Example(props) {
 const location = useLocation();

 const fetchData = () => {
  /* Calling the api */
 };

 const updateBreadcrumbs = () => {
  /* Updating the breadcrumbs*/
 };

 useEffect(() => {
  fetchData();
  updateBreadcrumbs();
 }, [location.pathname]);

 return (
  <div>
   <BreadCrumbs />
  </div>
 );
}

参考:

Five common mistakes writing react components (with hooks) in 2020

以上就是使用hooks写React组件需要注意的5个地方的详细内容,更多关于hooks写React组件的资料请关注脚本之家其它相关文章!

相关文章

  • react路由v6版本NavLink的两个小坑及解决

    react路由v6版本NavLink的两个小坑及解决

    这篇文章主要介绍了react路由v6版本NavLink的两个小坑及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • React Redux使用配置详解

    React Redux使用配置详解

    react-redux是redux官方react绑定库,能够使react组件从redux store中读取数据,并且向store分发actions以此来更新数据,这篇文章主要介绍了react-redux的设置,需要的朋友可以参考下
    2022-08-08
  • react配置代理setupProxy.js无法访问v3.0版本问题

    react配置代理setupProxy.js无法访问v3.0版本问题

    这篇文章主要介绍了react配置代理setupProxy.js无法访问v3.0版本问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • React实现文件分片上传和下载的方法详解

    React实现文件分片上传和下载的方法详解

    在当今的前端开发中,处理文件流操作已经成为一个常见的需求,无论是上传、下载、读取、展示还是其他的文件处理操作,都需要高效且可靠地处理二进制数据,本文将深入探讨如何使用 React 实现文件分片上传和下载,并介绍相关的基本概念和技术,需要的朋友可以参考下
    2023-08-08
  • React复制到剪贴板的示例代码

    React复制到剪贴板的示例代码

    本篇文章主要介绍了React复制到剪贴板的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • React实现监听粘贴事件并获取粘贴板中的截图

    React实现监听粘贴事件并获取粘贴板中的截图

    这篇文章主要介绍了React实现监听粘贴事件并获取粘贴板中的截图方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • React component.forceUpdate()强制重新渲染方式

    React component.forceUpdate()强制重新渲染方式

    这篇文章主要介绍了React component.forceUpdate()强制重新渲染方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • react自定义实现状态管理详解

    react自定义实现状态管理详解

    这篇文章主要为大家详细介绍了react如何自定义实现状态管理,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • 解析TypeError:import_react_native.AppState.removeEventListener is not a function

    解析TypeError:import_react_native.AppState.removeEventListener

    这篇文章主要为大家介绍了TypeError:import_react_native.AppState.removeEventListener is not a function问题解决分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • react使用css module无法重写bootstrap样式问题及解决

    react使用css module无法重写bootstrap样式问题及解决

    这篇文章主要介绍了react使用css module无法重写bootstrap样式问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11

最新评论