reactjs - React - 从高阶函数调用包装的组件回调
问题描述
我有一个包装服务调用的高阶函数。数据通过回调流式传输,我必须将其传递给包装的组件。我目前已经编写了下面的代码,其中子分配handleChange
给 HOC 传递的空对象。包装的组件是一个常规的 JS 网格,因此我必须调用 api 来添加数据,而不是将其作为道具传递。有更清洁的方法吗?
function withSubscription(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.handler = {};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange(row) {
if (typeof this.handler.handleChange === "function") {
this.handler.handleChange(row);
}
}
render() {
return <WrappedComponent serviceHandler={this.handler} {...this.props} />;
}
};
}
class MyGrid extends React.Component {
constructor(props) {
super(props);
if (props.serviceHandler !== undefined) {
props.serviceHandler.handleChange = this.handleChange.bind(this);
}
this.onReady = this.onReady.bind(this);
}
onReady(evt) {
this.gridApi = evt.api;
}
handleChange(row) {
this.gridApi.addRow(row);
}
render() {
return <NonReactGrid onReady={this.onReady} />;
}
}
const GridWithSubscription = withSubscription(MyGrid);
解决方案
那个被包裹的组件应该知道handler.handleChange
看起来很尴尬。
如果withSubscription
可以仅限于使用有状态组件,则组件可能会暴露changeHandler
钩子:
function withSubscription(WrappedComponent) {
return class extends React.Component {
...
wrappedRef = React.createRef();
handleChange = (row) => {
if (typeof this.wrappedRef.current.changeHandler === "function") {
this.wrappedRef.current.changeHandler(row);
}
}
render() {
return <WrappedComponent ref={this.wrappedRef}{...this.props} />;
}
};
}
class MyGrid extends React.Component {
changeHandler = (row) => {
...
}
}
const GridWithSubscription = withSubscription(MyGrid);
要使用有状态和无状态组件withSubscription
,应该更通用化,以便通过 props 与包装组件交互,即注册一个回调:
function withSubscription(WrappedComponent) {
return class extends React.Component {
handleChange = (row) => {
if (typeof this.changeHandler === "function") {
this.changeHandler(row);
}
}
registerChangeHandler = (cb) => {
this.changeHandler = cb;
}
render() {
return <WrappedComponent
registerChangeHandler={this.registerChangeHandler}
{...this.props}
/>;
}
};
}
class MyGrid extends React.Component {
constructor(props) {
super(props);
props.registerChangeHandler(this.changeHandler);
}
changeHandler = (row) => {
...
}
}
如果应用程序已经使用了某种形式的事件发射器,例如 RxJS 主题,则可以使用它们来代替handler.handleChange
父子之间的交互:
function withSubscription(WrappedComponent) {
return class extends React.Component {
changeEmitter = new Rx.Subject();
handleChange = (row) => {
this.changeEmitter.next(row);
}
render() {
return <WrappedComponent
changeEmitter={this.changeEmitter}
{...this.props}
/>;
}
};
}
class MyGrid extends React.Component {
constructor(props) {
super(props);
this.props.changeEmitter.subscribe(this.changeHandler);
}
componentWillUnmount() {
this.props.changeEmitter.unsubscribe();
}
changeHandler = (row) => {
...
}
}
为此目的传递主题/事件发射器在 Angular 中很常见,因为框架已经强加了对 RxJS 的依赖。
推荐阅读
- sql-server - 在 sql select 命令中使用自定义表别名而不是直接表名和列时,性能是否会下降?
- javascript - JS不能改变变量
- angular - 缺少所需的请求正文:public org.springframework.http.ResponseEntity<..model.Customer>
- angular - 角度重载模板
- embedded - 谁有更高优先级的 CPU 或 DMA 控制器?
- php - Laratrust 种子没有按预期工作
- android - 如何从 Google Play 游戏排行榜中获取玩家排名
- python - 当我尝试安装 pandas 时,我收到错误“没有名为 pandas 的模块”,但我确实安装了它
- graphics - 如何减少使用 three.js 编辑器制作的模型的加载时间?
- python - 我试图在 python 中将字符串转换为整数,但它不会让我