Javascript 在react/redux应用程序中,服务实例存放在何处?
假设我正在用Redux编写一个应用程序,任务是使用第三方库添加日志记录。其API如下:Javascript 在react/redux应用程序中,服务实例存放在何处?,javascript,reactjs,redux,testability,Javascript,Reactjs,Redux,Testability,假设我正在用Redux编写一个应用程序,任务是使用第三方库添加日志记录。其API如下: function createLogger(token) { // the logger has internal state! let logCount = 0; return { log(payload) { logCount++; // modify local state fetch('/
function createLogger(token) {
// the logger has internal state!
let logCount = 0;
return {
log(payload) {
logCount++; // modify local state
fetch('/someapi', { // ship payload to some API
method: 'POST',
body: payload
});
}
};
}
然后我会使用类似于以下内容的库:
let logger = createLogger('xyz');
logger.log('foobar');
我确实希望在应用程序初始化期间只创建一次记录器实例。但是问题是:我在哪里存储记录器实例
第一个办法是把它放在商店的某个地方。但这是个好主意吗?正如我在代码中演示的,logger对象是有状态的,它在闭包中存储一个计数器。我不会像对待不可变对象那样获得新实例。正如我们所知,状态只能通过纯减缩函数进行修改
其他可能性是在redux中间件闭包中的某个地方创建实例,或者只是创建一个全局变量,这在可测试性方面显然是有害的
对于这个(我认为)相当常见的场景,是否有最佳实践?由于您使用ES6模块,我会将您的记录器设置为一个模块,
导出它,然后导入它,无论您打算在哪里使用它。我认为从操作中记录日志是一个可靠的计划,因为它使组件不被察觉,并且不会因副作用而污染商店
function createLogger(token) {
// the logger has internal state!
let logCount = 0;
return {
log(payload) {
logCount++; // modify local state
fetch('/someapi', { // ship payload to some API
method: 'POST',
body: payload
});
}
};
}
export default const logger = createLogger('xyz');
你的行动创造者
import logger from 'logger-module';
//
logger.log('somestuff');
通过导入记录器并在其方法上放置您需要拦截的任何间谍/存根,仍然可以轻松实现测试。来自:
Raven
作为第三方库
如果库有自己的状态,那么在中间件中使用它不应该是一个问题(该状态属于库而不是您的应用程序)。如果出于某种原因正在为其创建状态,则该状态应属于Redux存储,可能位于store.logger或其他项下。是否使用ES6模块?组件是否会直接记录调用,或者记录是否由存储/操作自动完成?是的,我使用的是ES6模块。至于其他问题,我希望这些电话的自然位置是动作创作者通过redux thunk之类的东西。我不希望我的组件产生副作用。如果记录器本身对应用程序本身的状态没有副作用,那么它可能属于中间件。但是,代码中仍有一些地方不清楚。(1) 令牌参数的用途是什么?(2) logCount变量的用途是什么?(post请求中不包括令牌和日志计数。)(3)最后,有效负载是什么?它是从动作和/或状态派生的吗?(1)这只是记录器对象的一些配置。我可以想象对象本身使用该参数进行一些异步初始化(例如登录,然后同步返回记录器,并在登录完成后对日志调用进行排队)。(2) 当然,它本身是没有意义的,但我用它来表明记录器有某种内部状态,它会随着时间的推移而变化,而我不一定会得到一个新的实例。(3) 在实践中,这可能是从动作和/或状态派生的一些消息。现在把它放在中间件中对我来说是最好的。。。谢谢你的评论!因此,基本上,您可以使用记录器来测试操作,方法是使用一些库来覆盖使import statement import成为您模拟的对象,而不是真正的记录器,我理解正确了吗?您仍然可以导入真正的记录器。只要它的方法在使用之前被spy/stub替换,调用仍然会被拦截。它只是一个javascript对象,而监视/存根替换了它的属性。这只是标准的测试实践。对我来说,这在某种程度上类似于全局变量,希望您可以相对轻松地交换实现。但您无法创建redux应用程序的两个独立实例,因为您只能获得一个模块级记录器。如果有必要,您可以导出一个记录器工厂,该工厂根据键返回记录器。然后,每个应用程序都可以使用生成的密钥请求记录器,并且每个应用程序都有自己的单例。不过,我们开始陷入困境。
/**
* Sends crash reports as state is updated and listeners are notified.
*/
const crashReporter = store => next => action => {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
})
throw err
}
}