【发布时间】:2017-03-08 01:42:43
【问题描述】:
我有一个按名称分组的事件流。
每个生成的 observable 都作为 events$ 属性传递给 Folder 组件,该组件在 componentDidMount() 中订阅它。
我遇到的问题是,Folder 的观察者错过了第一个事件。
要重现,请单击添加事件。您会看到Folder 呈现undefined,并且不会将其更新为发出事件中的数据。 Playground
const events$ = new Rx.Subject();
class Folder extends React.Component {
constructor() {
super();
this.state = {};
}
componentDidMount() {
this.props.events$.subscribe(e => {
this.setState({
name: e.name,
permissions: e.permissions
});
});
}
componentWillUnmount() {
this.props.events$.unsubscribe();
}
render() {
const { name, permissions } = this.state;
return (
<div>
{`[${permissions}] ${name}`}
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super();
this.eventsByName$ = props.events$.groupBy(e => e.name);
this.state = {};
}
componentDidMount() {
this.eventsByName$.subscribe(folderEvents$ => {
const folder = folderEvents$.key;
this.setState({
[folder]: folderEvents$
});
});
}
onClick = () => {
this.props.events$.next({
type: 'ADD_FOLDER',
name: 'js',
permissions: 400
});
};
render() {
const folders = Object.keys(this.state);
return (
<div>
<button onClick={this.onClick}>
Add event
</button>
<div>
{
folders.map(folder => (
<Folder events$={this.state[folder]} key={folder} />
))
}
</div>
</div>
);
}
}
ReactDOM.render(
<App events$={events$} />,
document.getElementById('app')
);
<head>
<script src="https://unpkg.com/rxjs@5.2.0/bundles/Rx.js"></script>
<script src="https://unpkg.com/react@15.4.2/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.4.2/dist/react-dom.js"></script>
</head>
<body>
<div id="app"></div>
</body>
为了获取丢失的事件,我使用了ReplaySubject(1):Playground
const events$ = new Rx.Subject();
class Folder extends React.Component {
constructor() {
super();
this.state = {};
}
componentDidMount() {
this.props.events$.subscribe(e => {
this.setState({
name: e.name,
permissions: e.permissions
});
});
}
componentWillUnmount() {
this.props.events$.unsubscribe();
}
render() {
const { name, permissions } = this.state;
return (
<div>
{`[${permissions}] ${name}`}
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super();
this.eventsByName$ = props.events$.groupBy(e => e.name);
this.state = {};
}
componentDidMount() {
this.eventsByName$.subscribe(folderEvents$ => {
const folder = folderEvents$.key;
const subject$ = new Rx.ReplaySubject(1);
folderEvents$.subscribe(e => subject$.next(e));
this.setState({
[folder]: subject$
});
});
}
onClick = () => {
this.props.events$.next({
type: 'ADD_FOLDER',
name: 'js',
permissions: 400
});
};
render() {
const folders = Object.keys(this.state);
return (
<div>
<button onClick={this.onClick}>
Add event
</button>
<div>
{
folders.map(folder => (
<Folder events$={this.state[folder]} key={folder} />
))
}
</div>
</div>
);
}
}
ReactDOM.render(
<App events$={events$} />,
document.getElementById('app')
);
<head>
<script src="https://unpkg.com/rxjs@5.2.0/bundles/Rx.js"></script>
<script src="https://unpkg.com/react@15.4.2/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.4.2/dist/react-dom.js"></script>
</head>
<body>
<div id="app"></div>
</body>
现在,当点击 Add event 时,Folder 的观察者会看到该事件并正确呈现其数据。
这对我来说有点 hacky。
有没有更好的方法来组织代码以避免丢失事件的问题?
This question 可能会有所帮助。
【问题讨论】:
-
我摆弄了您的代码,看起来第一次流没有真正正确设置,但
groupBy操作员吞下了错误。这是显示错误的“版本”:webpackbin.com/bins/-KeiIf-k2_Utqbn4Zw2u -
这似乎是 React 和 Rxjs 之间的时间问题。
-
@SebastianSebald 看看this question。