详解React中共享组件逻辑的三种方式

 更新时间:2021年02月02日 16:46:53   作者:Null2020  
这篇文章主要介绍了详解React中共享组件逻辑的三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

废话少说,这三种方式分别是:render props、高阶组件和自定义Hook。下面依次演示

假设有一个TimeOnPage组件专门用来记录用户在当前页面停留时间,像这样:

const TimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return (
  <div>停留时间:{second}秒</div>
 );
}

如果另一个组件需要复用这个功能,我们能否封装一下,以便轻松地与其它组件共享?

一般很自然地想到子组件嵌套的方式,利用props传参

const Child = (props) => {
 return <div>stayTime: {props.stayTime}s</div>;
};

const TimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return (
  <div>
   <Child stayTime={second} />
  </div>
 );
}

这属于在 TimeOnPage组件内部硬编码,还没有达到封装复用的目标。看看render props怎么做?

render props

“render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术

接上文,在TimeOnPage里定义一个值为函数的prop,想渲染什么组件,在函数里返回即可,函数的参数就是想要共享的state。

const Child = (props) => {
 return <div>stayTime: {props.stayTime}s</div>;
};

const TimeOnPage = (props) => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return <div>{props.render(second)}</div>;
};

<TimeOnPage render={(stayTime) => <Child stayTime={stayTime} />

其实,render prop 就是一个用于告知组件需要渲染什么内容的函数prop。
React Router也用到了这项技术。

<Router>
 <Route path="/home" render={() => <div>Home</div>} />
</Router>

高阶组件

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

高阶组件是一个函数,参数是一个需要被复用的组件A,返回值是一个新的组件N。新组件N是在组件A的基础上做了一些加工,但不会修改组件A本身,只是功能增强。

假设有一个新闻列表组件长这样:

const NewList = () => {
 return (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
}

想要在新闻列表加载期间显示loading动画组件 <Loading />,通常会这么做

const Loading = () => {
 // loading动画
}
const NewList = ({ isLoading }) => {
 return isLoading ? (
  <Loading />
 ) : (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
};

假设现在Table组件也要在加载数据期间显示loading动画组件,遵循类似的模式

const Loading = () => {
 // loading动画
}
const DataList = ({ isLoading, ...props }) => {
 return isLoading ? (
  <Loading />
 ) : (
  <Table {...props} />
 );
};

以上,你会发现DataList和NewList结构极度相似,如果还有第三个、第四个组件要加loading,继续照这个模式重复第三次、第四次吗?这不是最理想的做法,更好的做法是,使用高阶组件把这个模式抽象出来:

const WithLoading = (WrappedComponent) => {
 return ({isLoading, ...props}) => {
  return isLoading ? <Loading /> : <WrappedComponent {...props} />;
 }
};

然后就可以在不修改NewList和DataList的情况下分别给他们增加loading

const NewList = () => {
 return (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
};

const DataList = (props) => {
 return <Table {...props} />
};

const WithLoading = (WrappedComponent) => {
 return ({isLoading, ...props}) => {
  return isLoading ? <Loading /> : <WrappedComponent {...props} />;
 }
};
// 带loading的NewList
const WithLoadingNewList = WithLoading(<NewList />)
// 带loading的DataList
const WithLoadingDataList = WithLoading(<DataList />)

自定义Hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

React Hook有useState、useEffect等,它们都是函数,自定义Hook也是一个函数,它的名称同样以use开头,函数内部可以调用其它Hook。与React组件不同的是,自定义Hook可以没有返回值。与普通函数不同的是,自定义Hook内部可以调用其它Hook,而普通函数则不行。

在写业务逻辑过程中,一般会将一些可重用的的方法定义成工具函数,然后就可以到处复用。同样,通过自定义 Hook,可以将组件逻辑提取到可重用的函数中。到底选择自定义Hook还是工具函数,取决于要提取的组件逻辑需不需要用到其他Hook,如果需要,就选择自定义Hook,否则用工具函数即可。

回到本文第一个 TimeOnPage组件,改成自定义Hook的形式

const useTimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return second;
}

使用方法

const Demo = () => {
 const stayTime = useTimeOnPage();
 return <div>当前页面停留时间:{stayTime}秒</div>
}

总结

三种共享组件逻辑的方式有各自的适用场景:
render props适合共享那些有不同子组件/子元素的父组件,子组件/子元素的“坑位”已经定义好了,只能渲染在指定位置;
高阶组件适合在不修改原有组件的基础上对组件进行扩展;
自定义Hook能做的,纯函数基本上也能做,只是有时候用自定义Hook实现会更方便快捷。
本文链接:Github

 到此这篇关于详解React中共享组件逻辑的三种方式的文章就介绍到这了,更多相关React 共享组件逻辑内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用reactjs优化了进度条页面性能提高70%

    使用reactjs优化了进度条页面性能提高70%

    这篇文章主要介绍了使用reactjs优化了进度条后页面性能提高了70%的操作技巧,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • React使用Context与router实现权限路由详细介绍

    React使用Context与router实现权限路由详细介绍

    这篇文章主要介绍了React使用Context与router实现权限路由的详细过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • React Native实现地址挑选器功能

    React Native实现地址挑选器功能

    这篇文章主要为大家详细介绍了React Native仿地址挑选器功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • react antd-mobile ActionSheet+tag实现多选方式

    react antd-mobile ActionSheet+tag实现多选方式

    这篇文章主要介绍了react antd-mobile ActionSheet+tag实现多选方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • React通过父组件传递类名给子组件的实现方法

    React通过父组件传递类名给子组件的实现方法

    React 是一个用于构建用户界面的 JAVASCRIPT 库。这篇文章主要介绍了React通过父组件传递类名给子组件的方法,需要的朋友可以参考下
    2017-11-11
  • 如何深入理解React的ref 属性

    如何深入理解React的ref 属性

    关于 Refs ,React 官网讲解的对于新手来说不太友好,还是自己一字一句解读后并以代码验证的方式后真正理解的.
    2021-05-05
  • 解决React报错JSX element type does not have any construct or call signatures

    解决React报错JSX element type does not have any construct

    这篇文章主要为大家介绍了解决React报错JSX element type does not have any construct or call signatures,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • React 中使用 Redux 的 4 种写法小结

    React 中使用 Redux 的 4 种写法小结

    这篇文章主要介绍了在 React 中使用 Redux 的 4 种写法,Redux 一般来说并不是必须的,只有在项目比较复杂的时候,比如多个分散在不同地方的组件使用同一个状态,本文就React使用 Redux的相关知识给大家介绍的非常详细,需要的朋友参考下吧
    2022-06-06
  • react map使用方法实例详解

    react map使用方法实例详解

    map()方法是在React中常用的数组处理方法之一,可以用于遍历数组、生成组件列表以及进行数据转换等操作,通过合理运用map()方法,可以更灵活地处理和展示数据,下面给大家讲解react map使用方法,感兴趣的朋友一起看看吧
    2023-10-10
  • 详解关于react-redux中的connect用法介绍及原理解析

    详解关于react-redux中的connect用法介绍及原理解析

    本篇文章主要介绍了详解关于react-redux中的connect用法介绍及原理解析,非常具有实用价值,需要的朋友可以参考下
    2017-09-09

最新评论