Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在react/redux应用程序中,服务实例存放在何处?_Javascript_Reactjs_Redux_Testability - Fatal编程技术网

Javascript 在react/redux应用程序中,服务实例存放在何处?

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('/

假设我正在用Redux编写一个应用程序,任务是使用第三方库添加日志记录。其API如下:

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
  }
}