如何将React状态绑定到RxJS可观察流
How to bind React state to RxJS observable stream?
有人能帮我如何将React State绑定到RxJS Observable吗?我做了类似的事情
componentDidMount() {
let source = Rx.Observable.of(this.state.val)
}
理想的结果是,每当this.state.val
更新(通过this.setState(...)
)时,source
也会更新,所以我可以将source
与其他RxJS可观测流相结合。
然而,在这种情况下,即使在this.state.val
被更新并且组件被重新渲染之后,source
也只被更新一次。
// Ideal result:
this.state.val = 1
source.subscribe(val => console.log(x)) //=> 1
this.state.val = 2
source.subscribe(val => console.log(val)) //=> 2
// Real result:
this.state.val = 1
source.subscribe(val => console.log(x)) //=> 1
this.state.val = 2
source.subscribe(val => console.log(val)) //=> 1 ???WTH
这可能是因为componentDidMount()
在React生命周期中只调用过一次。所以我把CCD_ 8移到CCD_。然而,结果仍然是一样的。
所以问题是如何在this.state.val
更新时使source
更新
更新:这是我用来解决问题的解决方案,使用Rx.Subject
// Component file
constructor() {
super(props)
this.source = new Rx.Subject()
_onChangeHandler(e) {
this.source.onNext(e.target.value)
}
componentDidMount() {
this.source.subscribe(x => console.log(x)) // x is updated
}
render() {
<input type='text' onChange={this._onChangeHandler} />
}
//
更新
要抽象出以下一些复杂性,请使用recompose的mapPropsStream或componentFromStream。例如
const WithMouseMove = mapPropsStream((props$) => {
const { handler: mouseMove, stream: mouseMove$ } = createEventHandler();
const mousePosition$ = mouseMove$
.startWith({ x: 0, y: 0 })
.throttleTime(200)
.map(e => ({ x: e.clientX, y: e.clientY }));
return props$
.map(props => ({ ...props, mouseMove }))
.combineLatest(mousePosition$, (props, mousePosition) => ({ ...props, ...mousePosition }));
});
const DumbComponent = ({ x, y, mouseMove }) => (
<div
onMouseMove={mouseMove}
>
<span>{x}, {y}</span>
</div>
);
const DumbComponentWithMouseMove = WithMouseMove(DumbComponent);
原始帖子
对于OP更新后的答案的一个稍微更新的答案,使用rxjs5,我提出了以下内容:
class SomeComponent extends React.Component {
constructor(props) {
super(props);
this.mouseMove$ = new Rx.Subject();
this.mouseMove$.next = this.mouseMove$.next.bind(this.mouseMove$);
this.mouseMove$
.throttleTime(1000)
.subscribe(idx => {
console.log('throttled mouse move');
});
}
componentWillUnmount() {
this.mouseMove$.unsubscribe();
}
render() {
return (
<div
onMouseMove={this.mouseMove$.next}
/>
);
}
}
一些值得注意的补充:
onNext()
现在是next()
- 绑定可观察的
next
方法可以将其直接传递给mouseMove处理程序 - 应在
componentWillUnmount
挂钩中取消订阅流
此外,在组件constructor
钩子中初始化的主题流可以作为属性传递给1+个子组件,这些子组件都可以使用任何可观察的next/error/complete方法推送到流。下面是我放在一起的一个jsbin示例,演示了多个组件之间共享的多个事件流。
很好奇是否有人对如何更好地封装这种逻辑以简化绑定和取消订阅等内容有想法。
一个选项可以是使用Rx.Observable.ofObjectChanges
>参见https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/ofobjectchanges.md
。
但是:
- 它使用
Object.observe
,这不是一个标准功能,因此在一些浏览器中必须进行聚合填充,并且实际上正在从ecmascript中删除(参见。http://www.infoq.com/news/2015/11/object-observe-withdrawn)。这不是未来的选择,但它很容易使用,所以如果它只是为了你自己的需要,为什么不呢
另一种选择是根据您的用例,以三种方法之一使用主题:shouldComponentUpdate
、componentWillUpdate
、componentDidUpdate
。查阅https://facebook.github.io/react/docs/component-specs.html用于执行每个功能时。在其中一种方法中,您将检查this.state.val
是否已更改,如果更改了,则会在主题上发出其新值。
我不是reactjs
专家,所以我想它们可能是其他选择。
尽管主题会起作用,但我认为最好的做法是在可以使用可观察对象时避免使用主题。在这种情况下,您可以使用Observable.fromEvent
:
class MouseOverComponent extends React.Component {
componentDidMount() {
this.mouseMove$ = Rx.Observable
.fromEvent(this.mouseDiv, "mousemove")
.throttleTime(1000)
.subscribe(() => console.log("throttled mouse move"));
}
componentWillUnmount() {
this.mouseMove$.unsubscribe();
}
render() {
return (
<div ref={(ref) => this.mouseDiv = ref}>
Move the mouse...
</div>
);
}
}
ReactDOM.render(<MouseOverComponent />, document.getElementById('app'));
这是代码笔上的。。。。
在我看来,在其他时候,Subject是最好的选择,比如当事件发生时,自定义React组件执行函数。
我强烈建议阅读这篇关于使用RxJS:将道具流式传输到React组件的博客文章
https://medium.com/@fahad19/使用-rxjs-with-react-js-part-2-streaming-pros-to-component-c7792bc1f40f
它使用FrintJS,并应用observe
高阶组件以流形式返回道具:
import React from 'react';
import { Observable } from 'rxjs';
import { observe } from 'frint-react';
function MyComponent(props) {
return <p>Interval: {props.interval}</p>;
}
export default observe(function () {
// return an Observable emitting a props-compatible object here
return Observable.interval(1000)
.map(x => ({ interval: x }));
})(MyComponent);
您可以使用钩子来完成。
这是的代码示例
import { Observable, Subscription } from 'rxjs';
import { useState, useEffect } from 'react';
export default function useObservable<T = number | undefined>(
observable: Observable<T | undefined>,
initialState?: T): T | undefined {
const [state, setState] = useState<T | undefined>(initialState);
useEffect(() => {
const subscription: Subscription = observable.subscribe(
(next: T | undefined) => {
setState(next);
},
error => console.log(error),
() => setState(undefined));
return () => subscription.unsubscribe();
}, [observable])
return state;
}
- 在rxjs中巧妙的蒸汽可观察合并
- 如何仅在RxJs中可观察到的源发出的特定错误上重试
- 使用rxjs创建一个可观察的对象,该对象稍后将连接到web套接字
- 我能在“;subscribe()"在Angular2中可观察到的RXJS中
- RxJS:我怎样才能用可观察量做一个“如果”
- RxJS:延迟可观察量的项生成
- RxJS 组合可观察量
- 操作 RxJS 流并发布结果的可观察量的正确方法是什么?
- 使用 Angular 2/RxJs 5 beta 可观察从 while 循环流式传输数据
- RXJS 可观察评估多次
- RxJS测试可观察序列,无需传递调度程序
- Rxjs 包装来自 D3 的其他库函数(可观察)
- RxJs 可观察的 zip 可观察数组
- 强制完成 RXJS 观察器
- 如何启动和停止 RXJS 中可观察到的间隔
- 重新调用返回 Rxjs 可观察的函数
- RXJS,如果可观察为条件
- RxJS:可观察器和单个观察器的递归列表
- 如何将promise序列转换为Rx.用RxJS观察对象
- Rxjs观察对象的更新和变化