首页 > 解决方案 > React 中的事件驱动方法?

问题描述

我想在一个组件中“触发一个事件”,并让其他组件“订阅”该事件并在 React 中做一些工作。

例如,这是一个典型的 React 项目。

我有一个模型,从服务器获取数据,并使用该数据呈现几个组件。

interface Model {
   id: number;
   value: number;
}

const [data, setData] = useState<Model[]>([]);
useEffect(() => {
   fetchDataFromServer().then((resp) => setData(resp.data));
}, []);

<Root>
   <TopTab>
     <Text>Model with large value count:  {data.filter(m => m.value > 5).length}</Text>
   </TobTab>
   <Content>
      <View>
         {data.map(itemData: model, index: number) => (
            <Item key={itemData.id} itemData={itemData} />
         )}
      </View>
   </Content>
   <BottomTab data={data} />
</Root>

在一个子组件中,可以编辑和保存模型。

const [editItem, setEditItem] = useState<Model|null>(null);
<Root>
   <TopTab>
     <Text>Model with large value count:  {data.filter(m => m.value > 5).length}</Text>
   </TobTab>
   <ListScreen>
      {data.map(itemData: model, index: number) => (
          <Item 
             key={itemData.id} 
             itemData={itemData} 
             onClick={() => setEditItem(itemData)}
          />
      )}
   </ListScreen>
   {!!editItem && (
       <EditScreen itemData={editItem} />
   )}
   <BottomTab data={data} />
</Root>

假设它是 EditScreen:

const [model, setModel] = useState(props.itemData);

<Input 
   value={model.value}
   onChange={(value) => setModel({...model, Number(value)})}
/>
<Button 
   onClick={() => {
       callSaveApi(model).then((resp) => {
           setModel(resp.data);
           // let other components know that this model is updated
       })
   }}
/>

App 必须让TopTab,BottomTabListScreen组件更新数据

为了有效地解决上述问题,我想用一个参数(更改的模型)触发一个事件(例如“模型更新”),并让其他组件订阅该事件并更改它们的数据,例如:

// in EditScreen
updateData().then(resp => {
   const newModel = resp.data;
   setModel(newModel);
   Event.emit("model-updated", newModel);
});

// in any other components
useEffect(() => {
   // subscribe model change event
   Event.on("model-updated", (newModel) => {
      doSomething(newModel);
   });
   // unsubscribe events on destroy
   return () => {
     Event.off("model-updated");
   }
}, []);

// in another component
useEffect(() => {
   // subscribe model change event
   Event.on("model-updated", (newModel) => {
      doSomethingDifferent(newModel);
   });
   // unsubscribe events on destroy
   return () => {
     Event.off("model-updated");
   }
}, []);

是否可以使用 React 钩子?

如何在 React 钩子中实现事件驱动的方法?

标签: reactjsreact-nativereact-hooksevent-driven

解决方案


无法替代事件发射器,因为 React 挂钩和使用上下文取决于 dom 树的深度并且范围有限。

将 EventEmitter 与 React(或 React Native)一起使用是否被认为是一种好习惯?

A: 是的,当 dom 树中有很深的组件时,这是一个很好的方法

我正在寻找 React 中的事件驱动方法。我现在对我的解决方案很满意,但我可以用 React hooks 实现同样的目标吗?

A:如果您指的是组件状态,那么钩子将无法帮助您在组件之间共享它。组件状态是组件本地的。如果您的状态存在于上下文中,那么 useContext 挂钩会很有帮助。对于 useContext 我们必须使用 and 实现完整的上下文 API,MyContext.Provider并且MyContext.Consumer必须包装在高阶(HOC)组件 Ref

所以事件发射器是最好的。

在 react native 中,你可以使用react-native-event-listeners

yarn add react-native-event-listeners

发件人组件

import { EventRegister } from 'react-native-event-listeners'

const Sender = (props) => (
    <TouchableHighlight
        onPress={() => {
            EventRegister.emit('myCustomEvent', 'it works!!!')
        })
    ><Text>Send Event</Text></TouchableHighlight>
)

接收器组件

class Receiver extends PureComponent {
    constructor(props) {
        super(props)
        
        this.state = {
            data: 'no data',
        }
    }
    
    componentWillMount() {
        this.listener = EventRegister.addEventListener('myCustomEvent', (data) => {
            this.setState({
                data,
            })
        })
    }
    
    componentWillUnmount() {
        EventRegister.removeEventListener(this.listener)
    }
    
    render() {
        return <Text>{this.state.data}</Text>
    }
}

推荐阅读