React - 从高阶函数调用包装的组件回调
React - Call wrapped component callback from higher order function
我有一个包装服务调用的高阶函数。数据在回调中流式传输,我必须将其传递给包装的组件。目前我已经编写了下面的代码,其中 child 将 handleChange
分配给 HOC 传递的空 object。包装的组件是一个常规的 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) => {
...
}
}
为此目的传递 subjects/event 发射器在 Angular 中很常见,因为框架已经强加了对 RxJS 的依赖。
我有一个包装服务调用的高阶函数。数据在回调中流式传输,我必须将其传递给包装的组件。目前我已经编写了下面的代码,其中 child 将 handleChange
分配给 HOC 传递的空 object。包装的组件是一个常规的 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) => {
...
}
}
为此目的传递 subjects/event 发射器在 Angular 中很常见,因为框架已经强加了对 RxJS 的依赖。