使用React开发H5是常规的做法,本文就开发实践中遇到的H5开发实现跨页面通讯功能作以记录,希望能够帮助有相同需求的同学。
1. 首先,如果你使用的是React的类组件
如果你的页面是通过React的类组件构建的,那么非常推荐使用Hook来完成这一任务。
1.1. 自定义Hook的基础
自定义Hook允许我们将组件逻辑提取成可重用的函数。在React 16.8之前,状态和副作用的管理通常需要依赖于类组件和生命周期方法。这不仅使得代码重用变得复杂,还增加了组件间状态共享的难度。自定义Hook的出现,使得这些问题迎刃而解。
1.2. 自定义useStorageEvent
Hook解析
自定义的useStorageEvent
是一个专门用于监听localStorage
中特定键变化的Hook。当指定的键值发生变化时,它将执行提供的回调函数。这在多个组件需要响应相同的存储事件时尤其有用。
1.2.1 实现细节
useStorageEvent
Hook利用了React的useEffect
Hook来处理副作用------在这个场景中,即是添加和移除事件监听器。useEffect
接受一个函数作为参数,这个函数会在组件渲染到屏幕之后执行。更重要的是,useEffect
返回的函数会在组件卸载时执行,提供了一个自然的方式来进行清理操作。
javascript
useEffect(() => {
const handleStorageChange = (event) => {
if (event.key === refreshKey) {
renderPageByData();
}
};
window.addEventListener('storage', handleStorageChange, false);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, [refreshKey, renderPageByData]);
在上述代码中,useEffect
的依赖数组[refreshKey, renderPageByData]
确保了当这些依赖发生变化时,副作用可以重新执行。这是处理外部事件监听(如localStorage
事件)时保持响应性的关键。
1.2.2 事件监听与副作用清理
通过window.addEventListener
注册了一个storage
事件监听器,当localStorage
发生变化时,会调用handleStorageChange
函数。如果变化的键匹配refreshKey
,则执行renderPageByData
回调。利用useEffect
的清理机制,通过window.removeEventListener
移除事件监听器,避免了内存泄漏和无效的事件处理。
1.3. 自定义Hook的优势
- 复用性:将逻辑提取到自定义Hook中,可以在多个组件之间共享逻辑,避免了代码的重复。
- 组织性:自定义Hook允许按逻辑而非生命周期方法组织代码,使得相关代码更加紧密,易于理解和维护。
- 解耦:自定义Hook帮助将复杂组件拆分成更小、更专注的函数,降低组件间的耦合。
1.4. 完整代码展示
javascript
import { useEffect } from 'react';
export const useStorageEvent = (refreshKey, renderPageByData) => {
useEffect(() => {
const handleStorageChange = (event) => {
if (event.key === refreshKey) {
renderPageByData();
}
};
window.addEventListener('storage', handleStorageChange, false);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, [refreshKey, renderPageByData]);
};
通过useStorageEvent
这个例子,我们看到自定义Hook为处理复杂逻辑提供了一种优雅的方法,使得代码不仅易于重用,而且更加清晰和可维护。在现代Web开发实践中,充分利用自定义Hook的优势,可以极大提高开发效率和应用性能。
2. 其次,如果你很不幸的使用了类组件
对于一些老项目来说,业务逻辑都是用React的类组件来写的,因此不能直接使用Hook,这个时候只能退而求其次使用高阶组件实现逻辑复用。
2.1. 高阶组件(HOC)的应用实例
以withStorageListener
为例,此高阶组件旨在为React类组件提供对localStorage
事件的监听功能。当指定的localStorage
键值发生变化时,执行预注册的回调函数,从而响应这一变化。这对于需要在多个位置监听并响应相同localStorage
变化的应用尤其有用。
2.1.1 实现细节
withStorageListener
高阶组件通过封装一个React类组件来实现。在这个类组件的生命周期方法componentDidMount
中注册storage
事件监听器,在componentWillUnmount
中移除监听器。这保证了只有在组件被挂载时监听器才会被添加,而在组件卸载时,相关资源会被正确清理,避免潜在的内存泄露问题。
javascript
function withStorageListener(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.handleStorageChange = this.handleStorageChange.bind(this);
this.registerCb = { exec: () => {} }
}
componentDidMount() {
window.addEventListener('storage', this.handleStorageChange, false);
}
componentWillUnmount() {
window.removeEventListener('storage', this.handleStorageChange);
this.registerCb = null;
}
handleStorageChange(event) {
if (event.key === WrappedComponent.refreshKey) {
if(this.registerCb) this.registerCb.exec();
}
}
render() {
return <WrappedComponent {...this.props} registerCb={this.registerCb} />;
}
};
}
2.1.2 高阶组件的优势
- 逻辑复用:HOC使得跨组件的逻辑复用成为可能,尤其适用于将相同的逻辑应用到多个组件上。
- 抽象和隔离:HOC可以将复杂的逻辑和状态抽象隔离,简化被包装组件的实现,使其更关注于渲染逻辑。
- 链式组合:HOC可以被链式组合使用,为组件逐步增加多个功能或增强。
2.2 比较
虽然高阶组件和自定义Hook各有千秋,它们在React生态中都扮演着重要角色。高阶组件以其强大的逻辑封装和复用能力,依旧是React应用开发中不可或缺的一部分。而自定义Hook则以其简洁和直观的用法,为函数式组件提供了强大的状态管理和逻辑复用能力。
javascript
// 导出高阶组件
export { withStorageListener };
高阶组件和自定义Hook不是相互排斥的,它们可以根据不同的场景和需求被灵活选用。例如,对于需要在函数式组件中共享逻辑的情况,自定义Hook可能是更佳选择;而对于希望在多个类组件中复用逻辑的场景,高阶组件则能够发挥其独特的优势。正确地理解和运用这两种模式,将有助于提高React应用的开发效率和代码的可维护性。
3. 结尾
本文从实际开发的一个需求入手,不仅记录了如何解决H5开发过程中跨页面通讯的问题,还结合代码对比了两种逻辑复用解决方案,即Hook和HOC的不同。