React多个组件基于一个信息进行组件的响应变化,请问有方便的方式进行实现吗?

image.png
需求:
组件A点击状态切换按钮,发起状态变化(需要传递数据:args),然后:
组件B1,组件B2,组件C1 都会依据此args进行相应的内容变化。

请问这样的功能一般是怎么实现?
1、是可以组件B1,B2,C1都通过监听事件实现吗?
2、还是说通过React的客户端状态实现,比如:zustand进行状态的记录来实现?(这种应该不是很好,因为不是forwardRefs来进行实时的执行)。是否有方便的方式来实现呢(比如使用三方库)?
3、请问如果是监听,是B1,B2,C1这样的子组件来直接监听好,还是B,C组件这样的组件来监听,然后再使用forwardRefs来对B1,B2,C1进行执行变化?

阅读 1k
avatarAI BotBETA

在React中实现多个组件基于一个状态变化进行响应,通常可以通过几种方式来实现。以下是一些推荐的方法和解释:

1. 使用React Context API

React的Context API非常适合跨组件层级传递数据,而无需手动通过每个层级组件传递props。你可以创建一个Context来包含你的状态(如args)和修改这个状态的函数。然后,所有需要这个状态的组件都可以从这个Context中订阅它。

步骤

  1. 创建一个Context来保存状态和更新状态的函数。
  2. 在组件树中较高的层级(如App组件)中包裹你的Context.Provider,并传递状态值和更新函数。
  3. 在需要这个状态的组件中使用useContext钩子来订阅这个Context。

示例代码

// MyContext.js
import React, { createContext, useState } from 'react';

const MyContext = createContext({
  args: null,
  setArgs: () => {},
});

export const MyContextProvider = ({ children }) => {
  const [args, setArgs] = useState(null);

  return (
    <MyContext.Provider value={{ args, setArgs }}>
      {children}
    </MyContext.Provider>
  );
};

export default MyContext;

// 组件A, B1, B2, C1中使用MyContext

2. 使用全局状态管理库(如Redux, Zustand等)

如果你的应用很大或者状态管理变得复杂,使用全局状态管理库可能是一个好主意。这些库提供了更强大和灵活的状态管理能力。

Zustand示例

// store.js
import create from 'zustand';

const useStore = create((set) => ({
  args: null,
  setArgs: (newArgs) => set(() => ({ args: newArgs })),
}));

export default useStore;

// 组件中使用
const args = useStore(state => state.args);
const setArgs = useStore(state => state.setArgs);

3. 监听事件

虽然监听事件(如使用useEffect来监听Redux store的变化或自定义事件)是一种可行的方法,但它通常不如使用Context或全局状态管理库那么直接和高效。特别是,如果你正在监听Redux store的变化,你可能需要使用Redux的useSelector钩子。

4. 组件间通信方式

  • 直接监听 vs 组件B/C监听:如果B1, B2, C1直接依赖于args,则它们应该直接监听这个状态的变化。如果它们共享一些共同的行为或状态,可以考虑将它们包裹在一个共同的父组件(如B或C)中,但这个父组件也应该是基于Context或全局状态来管理其子组件的状态。
  • forwardRefsforwardRefs主要用于将refs从父组件传递到子组件,而不是用于状态管理。在这个场景中,它可能不是最直接或最有效的解决方案。

结论

对于你的需求,推荐使用React的Context API或全局状态管理库(如Zustand)来实现跨组件的状态共享和响应。这些方法不仅简化了状态管理的复杂性,还提高了组件间的解耦程度。

3 个回答
  1. 事件监听
    这样做的话各个组件内部维护的是独立的状态,只是通过监听事件然后更新状态的方式做到了同步
  2. 状态管理
    多个组件共享状态可以使用 Zustand,Redux 等状态管理库
  3. 状态提升
    将公共状态提升到最近的公共父组件,在层级较多时 props 一层层传递较为繁琐
  4. Context
    类似状态提升,但是在最近公共父组件中使用 Context 提供状态,避免了 props 传递的麻烦。但是 Context 改变会导致该组件下的整个组件树重新渲染

先回答问题0.请问这样的功能一般是怎么实现?
这个功能有很多种实现方式,项目中如果有状态管理库的话,一般用状态管理库实现,比如你提到的zustand,如果没有的话可以用react context API实现,当然也可以用props或forward一层层传递数据,但这样并不灵活,所以很少会这样做;

接着回答问题1.是可以组件B1,B2,C1都通过监听事件实现吗?
可以,用状态管理库、react context API、或者eventemitter之类的三方库都可以实现;

问题2.如果觉得zustand麻烦,可以用react context API,但如果对性能有较高要求的话,建议还是用zustand,也可以用eventemitter这类的发布订阅库来实现,在3个组件内对点击事件进行监听,比较常见的有mitteventemitter2等;

问题3.子组件直接监听好,父组件监听会引起不必要的渲染。

用状态管理库 :

const useStore = create((set) => ({
  args: null,
  setArgs: (args) => set({ args })
}))

// 组件A
function ComponentA() {
  const setArgs = useStore(state => state.setArgs)
  
  return <button onClick={() => setArgs(newArgs)}>切换状态</button>
}

// 组件B1
function ComponentB1() {
  const args = useStore(state => state.args)
  useEffect(() => {
   
  }, [args])
}

用 Context + Provider

const ArgsContext = createContext()

function ArgsProvider({ children }) {
  const [args, setArgs] = useState(null)
  
  return (
    <ArgsContext.Provider value={{ args, setArgs }}>
      {children}
    </ArgsContext.Provider>
  )
}

// 组件里用
function ComponentB1() {
  const { args } = useContext(ArgsContext)
  // ...
}

用发布订阅模式:


const eventBus = {
  listeners: {},
  on(event, callback) {
    if (!this.listeners[event]) {
      this.listeners[event] = []
    }
    this.listeners[event].push(callback)
  },
  emit(event, data) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(cb => cb(data))
    }
  }
}

// 组件A
function ComponentA() {
  return <button onClick={() => eventBus.emit('argsChange', newArgs)}>
    切换状态
  </button>
}

// 组件B1 
function ComponentB1() {
  useEffect(() => {
    const handler = (args) => {
      // 处理更新
    }
    eventBus.on('argsChange', handler)
    return () => {
      // 清理监听
    }
  }, [])
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏