React 中的事件驱动方法? [英] Event-driven approach in React?

查看:62
本文介绍了React 中的事件驱动方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想触发一个事件";在一个组件中,让其他组件订阅"到那个事件并在 React 中做一些工作.

I'd like to "fire an event" in one component, and let other components "subscribe" to that event and do some work in React.

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

For example, here is a typical React project.

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

I have a model, fetch data from server and several components are rendered with that data.

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>

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

In one child component, a model can be edited and saved.

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:

Let's assume it's 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 必须让 TopTabBottomTabListScreen 组件更新数据

App must let TopTab, BottomTab and ListScreen component to update data

  • 无需再次从服务器调用 API(因为 EditScreen.updateData 已经从服务器获取更新的数据)和
  • 不将 updateData 函数作为 props 传递(因为在大多数实际情况下,组件结构太复杂,无法将所有函数作为 props 传递)
  • without calling API from server again (because EditScreen.updateData already fetched updated data from server) and
  • not passing updateData function as props (because in most real cases, components structure is too complex to pass all functions as props)

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

In order to solve above problem effectively, I'd like to fire an event (e.g. "model-update") with an argument (changed model) and let other components subscribe to that event and change their data, e.g.:

// 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 钩子?

Is it possible using React hooks?

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

推荐答案

无法替代事件发射器,因为 React 钩子和使用上下文依赖于 dom 树深度并且范围有限.

There cannot be an alternative of event emitter because React hooks and use context is dependent on dom tree depth and have limited scope.

在 React(或 React Native)中使用 EventEmitter 是否被认为是一种好习惯?

Is using EventEmitter with React (or React Native) considered to be a good practice?

A: 是的,当 dom 树中有很深的组件时最好接近

A: Yes it is a good to approach when there is component deep in dom tree

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

I'm seeking event-driven approach in React. I'm happy with my solution now but can I achieve the same thing with React hooks?

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

A: If you are referring to component state, then hooks will not help you share it between components. Component state is local to the component. If your state lives in context, then useContext hook would be helpful. For useContext we have to implement full context API with MyContext.Provider and MyContext.Consumer and have to wrap inside high order (HOC) component Ref

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

so event emitter is best.

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

In react native, you can use react-native-event-listeners package

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>
    }
}

这篇关于React 中的事件驱动方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆