reactjs - 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
,BottomTab
和ListScreen
组件更新数据
- 无需再次从服务器调用 API(因为 EditScreen.updateData 已经从服务器获取更新数据)和
- 不将
updateData
函数作为道具传递(因为在大多数实际情况下,组件结构太复杂而无法将所有函数作为道具传递)
为了有效地解决上述问题,我想用一个参数(更改的模型)触发一个事件(例如“模型更新”),并让其他组件订阅该事件并更改它们的数据,例如:
// 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 钩子中实现事件驱动的方法?
解决方案
无法替代事件发射器,因为 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>
}
}
推荐阅读
- javascript - 如何将自定义字体添加到 QuillJS 编辑器?
- sql-server - .NET Core API 无法通过 docker-compose 连接到数据库
- moqui - orderby lastUpdatedStamp in entity-find
- database - 实体、实体类型和实体实例之间有什么区别?
- python - 什么是 Python“系统库”?
- python - python docker如何打印脚本的返回码以了解测试脚本是通过还是失败
- python - Flask - 每个 HTTP 请求似乎都不是一个新的独立请求。这是为什么?
- python - Python pathlib:解析符号链接的完整路径而不遵循它
- linux - 是否可以从 x86(x64) windows 交叉编译到 x86(x64) linux?
- amazon-dynamodb - 如何使用带有 dynamodb 的 aws cli 查询名称包含“:”的索引?