克服Redux的缺点在React/Native中使用消息队列,pubsub-js更加简洁的组件间通信和状态传递方法


发布者 ourjs  发布时间 1732419889463
关键字 react hooks 

Redux是一个用于JavaScript应用的状态管理库,广泛应用于React应用中。

Redux的缺点

Redux是内存中的状态存储,每次状态更新都会返回新的状态对象,这可能会导致内存的过度使用。其内存占用高,性能差。因此更加不适合在 React Native 中使用。

Redux采用全局状态管理,但更多时侯,我们可能只需要一个用于组件间通信的消息中间件,dispatch 触发的状态,并不需要集中存储。使用Redux可能会显得繁重和冗余。

Redux的状态集中存储比较有利于状态的存储和恢复。比如如果Redux用localStorage持久化,这样用户刷新页面时,单页应用还可以恢复刷新之前的状态。但这种场景对于React native应用来说并不存在,性价比不高。

我们可以通过 PubSubJS 使用类似消息中间件(发布、订阅)的方法来管理组件间的通信和数据的传递,其本身并不存储状态和处理状态变化,极大的提高性能和简化开发流程,大概如下:

登陆组件->登陆->publish 登陆成功事件
父组件->subscribe登陆成功事件->切换到欢迎界面
欢迎界面->subscribe登陆成功事件->用登陆返回的token获取图片列表

使用这种方式的好处是,兄弟组件间通信不必再像使用props那种通过父组件来通信,多层组件之间通信也不必在一层一层的传递, 直接在触发事件的组件中发布消息 监听组件中订阅消息即可;

组件安装

添加消息中间件

yarn add pubsub-js

项目中如果用的typescript,添加类型声明文件,为IDE提供智能提示

yarn add -D @types/pubsub-js

消息发布

pubsub 的消息发布非常简单一行 publish 即可。比如这里有一个 Login 组件。当登陆成功后,要通知上级界面和欢迎界面切换视图。这里定义了事件类型 EventType。

import { publish } from 'pubsub-js';

export const EventType = {
    USER_SIGNIN: 'USER.SIGNIN',
    USER_SIGNUP: 'USER.SIGNUP',
}

type LoginParams = {
    style?: StyleProp<ViewStyle>;
}
 
const LoginPage = (params: LoginParams) => {
    const [username, setUsername] = React.useState('');
    const [password, setPassword] = React.useState('');

    const handleLogin = async() => {
        const isSuccess = await Login({ username, password })
        if (isSuccess) {
            console.log('event publish')
            publish(EventType.USER_SIGNIN, isSuccess)
        }
    };

消息订阅

消息的接受也非常简单,subscribe 即可。这里使用 useEffect 防止组件的重复渲染,造成事件的多次接收。

import { subscribe } from 'pubsub-js';

export enum PAGE_VIEW {
  HOMEPAGE,
  IMAGE_PLAYER,
  VIDEO_PLAYER,
  LOGINPAGE,
  WELCOMEPAGE,
}

let prevViewBeforeVideoOrImage = PAGE_VIEW.HOMEPAGE
let currentImageOrVideoIndex = 0

function App(): React.JSX.Element {
  const [ pageView, setPageView ] = useState(PAGE_VIEW.WELCOMEPAGE)

  useEffect(() => {
    subscribe(EventType.USER_SIGNIN, (message, isSuccess: boolean) => {
      console.log('recevied user logined', message, isSuccess)
      setPageView(PAGE_VIEW.HOMEPAGE)
    })
  }, [])

可见,PubSubJS 的使用非常简洁