我正在使用the suggestion from @gaearon在我的redux商店上设置一个监听器。我正在使用这种格式:
function observeStore(store, select, onChange) {
let currentState;
if (!Function.prototype.isPrototypeOf(select)) {
select = (state) => state;
}
function handleChange() {
let nextState = select(store.getState());
if (nextState !== currentState) {
currentState = nextState;
onChange(currentState);
}
}
let unsubscribe = store.subscribe(handleChange);
handleChange();
return unsubscribe;
}
我在onEnter
路由器的react-router
处理程序中使用它:
Entity.onEnter = function makeFetchEntity(store) {
return function fetchEntity(nextState, replace, callback) {
const disposeRouteHandler = observeStore(store, null, (state) => {
const conditions = [
isLoaded(state.thing1),
isLoaded(state.thing2),
isLoaded(state.thing3),
];
if (conditions.every((test) => !!test) {
callback(); // allow react-router to complete routing
// I'm done: how do I dispose the store subscription???
}
});
store.dispatch(
entities.getOrCreate({
entitiesState: store.getState().entities,
nextState,
})
);
};
};
基本上,当操作完成调度(异步)时,这有助于控制路由器的进程。
我的问题是我无法确定在哪里拨打disposeRouteHandler()
。如果我在定义之后立即调用它,我的onChange
函数永远不会有机会做到这一点,我不能把它放在onChange
函数中,因为它还没有定义。
在我看来是鸡蛋问题。非常感谢任何帮助/指导/见解。
答案 0 :(得分:1)
怎么样:
Entity.onEnter = function makeFetchEntity(store) {
return function fetchEntity(nextState, replace, callback) {
let shouldDispose = false;
const disposeRouteHandler = observeStore(store, null, (state) => {
const conditions = [
isLoaded(state.thing1),
isLoaded(state.thing2),
isLoaded(state.thing3),
];
if (conditions.every((test) => !!test) {
callback(); // allow react-router to complete routing
if (disposeRouteHandler) {
disposeRouteHandler();
} else {
shouldDispose = true;
}
}
});
if (shouldDispose) {
disposeRouteHandler();
}
store.dispatch(
entities.getOrCreate({
entitiesState: store.getState().entities,
nextState,
})
);
};
};
尽管使用observable
模式会导致一些买入,但您可以使用普通的js代码解决任何困难。或者,您可以修改您的observable以更好地满足您的需求。
例如:
function observeStore(store, select, onChange) {
let currentState, unsubscribe;
if (!Function.prototype.isPrototypeOf(select)) {
select = (state) => state;
}
function handleChange() {
let nextState = select(store.getState());
if (nextState !== currentState) {
currentState = nextState;
onChange(currentState, unsubscribe);
}
}
unsubscribe = store.subscribe(handleChange);
handleChange();
return unsubscribe;
}
和
Entity.onEnter = function makeFetchEntity(store) {
return function fetchEntity(nextState, replace, callback) {
const disposeRouteHandler = observeStore(store, null, (state, disposeRouteHandler) => {
const conditions = [
isLoaded(state.thing1),
isLoaded(state.thing2),
isLoaded(state.thing3),
];
if (conditions.every((test) => !!test) {
callback(); // allow react-router to complete routing
disposeRouteHandler();
}
}
store.dispatch(
entities.getOrCreate({
entitiesState: store.getState().entities,
nextState,
})
);
};
};
它确实为onChange
添加了一个奇怪的参数,但它只是众多方法中的一种。
核心问题是handleChange
在没有任何变化的情况下立即同步调用,以后再异步调用。它被称为Zalgo。
答案 1 :(得分:0)
受到@DDS建议的启发,我对@gaearon's comment中提到的其他模式提出了以下修改:
export function toObservable(store) {
return {
subscribe({ onNext }) {
let dispose = this.dispose = store.subscribe(() => {
onNext.bind(this)(store.getState())
});
onNext.bind(this)(store.getState());
return { dispose };
},
dispose: function() {},
}
}
这允许我调用:
Entity.onEnter = function makeFetchEntity(store) {
return function fetchEntity(nextState, replace, callback) {
toObservable(store).subscribe({
onNext: function onNext(state) {
const conditions = [/* many conditions */];
if (conditions.every((test) => !!test) {
callback(); // allow react-router to complete routing
this.dispose(); // remove the store subscription
}
},
});
store.dispatch(/* action */);
};
};
关键的区别在于我正在为onNext传递常规函数,以免干扰bind(this)
中的toObservable
;我无法弄清楚如何强制绑定使用我想要的上下文。
此解决方案avoids
向
添加一个奇怪的参数onChange
...在我看来也传达了更多的意图:this.dispose()
从onNext
内部调用,所以它有点像onNext.dispose()
,这正是我想要的做。