Not*_*112 5 react-native redux expo react-native-hermes
我正在使用Expo 49 Beta (React Native),它引入了 Hermes 的新调试功能。这意味着还集成了redux-devtools的react-native-debugger已被弃用。我尝试独立使用,但没有成功。redux-devtools
1.@redux-devtools/remote根据https://github.com/reduxjs/redux-devtools/issues/1382进行补丁
2.用于@redux-devtools/cli通过运行来启动本地服务器redux-devtools --port=8000 --open
3.设置商店
import {devToolsEnhancer} from '@redux-devtools/remote';
import {configureStore} from '@reduxjs/toolkit';
const store = configureStore({
reducer: rootReducer,
devTools: true,
enhancers: [
devToolsEnhancer({
name: Platform.OS,
port: 8000,
secure: false,
realtime: true,
}),
],
});
Run Code Online (Sandbox Code Playgroud)
4.运行应用程序
5.Redux DevTools设置
编辑:这已在最新版本中修复@redux-devtools/remote
显然,Hermes 引擎有问题for await。我设法通过修补@redux-devtools/remote/lib/cjs/devTools.js此 GitHub 问题来使其工作:https://github.com/reduxjs/redux-devtools/issues/1382#issuecomment-1615995161
patch-package\xe2\x98\x9d\xef\xb8\x8f 您可以在上面的链接中找到该补丁。由于StackOverflow支持不是```diff```很好,所以我没有在这里发布。
最终结果(在@redux-devtools/remote@0.8.0撰写本文时)应如下所示:
\'use strict\';\n\nvar _interopRequireDefault = require(\'@babel/runtime/helpers/interopRequireDefault\');\nObject.defineProperty(exports, \'__esModule\', {\n value: true,\n});\nexports.composeWithDevTools = composeWithDevTools;\nexports.default = void 0;\nvar _defineProperty2 = _interopRequireDefault(\n require(\'@babel/runtime/helpers/defineProperty\'),\n);\nvar _jsan = require(\'jsan\');\nvar _socketclusterClient = _interopRequireDefault(\n require(\'socketcluster-client\'),\n);\nvar _configureStore = _interopRequireDefault(require(\'./configureStore\'));\nvar _constants = require(\'./constants\');\nvar _rnHostDetect = _interopRequireDefault(require(\'rn-host-detect\'));\nvar _utils = require(\'@redux-devtools/utils\');\nfunction async(fn) {\n setTimeout(fn, 0);\n}\nfunction str2array(str) {\n return typeof str === \'string\'\n ? [str]\n : str && str.length > 0\n ? str\n : undefined;\n}\nfunction getRandomId() {\n return Math.random().toString(36).substr(2);\n}\nclass DevToolsEnhancer {\n constructor() {\n var _this = this;\n (0, _defineProperty2.default)(this, \'errorCounts\', {});\n (0, _defineProperty2.default)(this, \'send\', () => {\n if (!this.instanceId) {\n this.instanceId = (this.socket && this.socket.id) || getRandomId();\n }\n try {\n fetch(this.sendTo, {\n method: \'POST\',\n headers: {\n \'content-type\': \'application/json\',\n },\n body: JSON.stringify({\n type: \'STATE\',\n id: this.instanceId,\n name: this.instanceName,\n payload: (0, _jsan.stringify)(this.getLiftedState()),\n }),\n }).catch(function (err) {\n console.log(err);\n });\n } catch (err) {\n console.log(err);\n }\n });\n (0, _defineProperty2.default)(this, \'handleMessages\', message => {\n if (\n message.type === \'IMPORT\' ||\n (message.type === \'SYNC\' &&\n this.socket.id &&\n message.id !== this.socket.id)\n ) {\n this.store.liftedStore.dispatch({\n type: \'IMPORT_STATE\',\n\n nextLiftedState: (0, _jsan.parse)(message.state),\n });\n } else if (message.type === \'UPDATE\') {\n this.relay(\'STATE\', this.getLiftedState());\n } else if (message.type === \'START\') {\n this.isMonitored = true;\n if (typeof this.actionCreators === \'function\') {\n this.actionCreators = this.actionCreators();\n }\n this.relay(\'STATE\', this.getLiftedState(), this.actionCreators);\n } else if (message.type === \'STOP\' || message.type === \'DISCONNECTED\') {\n this.isMonitored = false;\n this.relay(\'STOP\');\n } else if (message.type === \'ACTION\') {\n this.dispatchRemotely(message.action);\n } else if (message.type === \'DISPATCH\') {\n this.store.liftedStore.dispatch(message.action);\n }\n });\n (0, _defineProperty2.default)(this, \'sendError\', errorAction => {\n // Prevent flooding\n if (errorAction.message && errorAction.message === this.lastErrorMsg) {\n return;\n }\n this.lastErrorMsg = errorAction.message;\n async(() => {\n this.store.dispatch(errorAction);\n if (!this.started) {\n this.send();\n }\n });\n });\n (0, _defineProperty2.default)(this, \'stop\', keepConnected => {\n this.started = false;\n this.isMonitored = false;\n if (!this.socket) {\n return;\n }\n void this.socket.unsubscribe(this.channel);\n this.socket.closeChannel(this.channel);\n if (!keepConnected) {\n this.socket.disconnect();\n }\n });\n (0, _defineProperty2.default)(this, \'start\', () => {\n if (\n this.started ||\n (this.socket && this.socket.getState() === this.socket.CONNECTING)\n ) {\n return;\n }\n this.socket = _socketclusterClient.default.create(this.socketOptions);\n void (async () => {\n let consumer = this.socket.listener(\'error\').createConsumer();\n while (true) {\n const {value: data, done} = await consumer.next();\n if (done) {\n break;\n }\n\n // for await (const data of this.socket.listener(\'error\')) {\n // if we\'ve already had this error before, increment it\'s counter, otherwise assign it \'1\' since we\'ve had the error once.\n\n this.errorCounts[data.error.name] = this.errorCounts.hasOwnProperty(\n data.error.name,\n )\n ? this.errorCounts[data.error.name] + 1\n : 1;\n if (this.suppressConnectErrors) {\n if (this.errorCounts[data.error.name] === 1) {\n console.log(\n \'remote-redux-devtools: Socket connection errors are being suppressed. \' +\n \'\\n\' +\n "This can be disabled by setting suppressConnectErrors to \'false\'.",\n );\n console.log(data.error);\n }\n } else {\n console.log(data.error);\n }\n }\n })();\n void (async () => {\n let consumer = this.socket.listener(\'connect\').createConsumer();\n while (true) {\n const {value: data, done} = await consumer.next();\n if (done) {\n break;\n }\n\n // for await (const data of this.socket.listener(\'connect\')) {\n console.log(\'connected to remotedev-server\');\n this.errorCounts = {}; // clear the errorCounts object, so that we\'ll log any new errors in the event of a disconnect\n this.login();\n }\n })();\n void (async () => {\n let consumer = this.socket.listener(\'disconnect\').createConsumer();\n while (true) {\n const {value: data, done} = await consumer.next();\n if (done) {\n break;\n }\n\n // for await (const data of this.socket.listener(\'disconnect\')) {\n this.stop(true);\n }\n })();\n });\n (0, _defineProperty2.default)(this, \'checkForReducerErrors\', function () {\n let liftedState =\n arguments.length > 0 && arguments[0] !== undefined\n ? arguments[0]\n : _this.getLiftedStateRaw();\n if (liftedState.computedStates[liftedState.currentStateIndex].error) {\n if (_this.started) {\n _this.relay(\n \'STATE\',\n (0, _utils.filterStagedActions)(liftedState, _this.filters),\n );\n } else {\n _this.send();\n }\n return true;\n }\n return false;\n });\n (0, _defineProperty2.default)(this, \'monitorReducer\', function () {\n let state =\n arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let action = arguments.length > 1 ? arguments[1] : undefined;\n _this.lastAction = action.type;\n if (\n !_this.started &&\n _this.sendOnError === 2 &&\n _this.store.liftedStore\n ) {\n async(_this.checkForReducerErrors);\n } else if (action.action) {\n if (\n _this.startOn &&\n !_this.started &&\n _this.startOn.indexOf(action.action.type) !== -1\n ) {\n async(_this.start);\n } else if (\n _this.stopOn &&\n _this.started &&\n _this.stopOn.indexOf(action.action.type) !== -1\n ) {\n async(_this.stop);\n } else if (\n _this.sendOn &&\n !_this.started &&\n _this.sendOn.indexOf(action.action.type) !== -1\n ) {\n async(_this.send);\n }\n }\n return state;\n });\n (0, _defineProperty2.default)(this, \'enhance\', function () {\n let options =\n arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this.init({\n ...options,\n hostname: (0, _rnHostDetect.default)(options.hostname || \'localhost\'),\n });\n const realtime =\n typeof options.realtime === \'undefined\'\n ? process.env.NODE_ENV === \'development\'\n : options.realtime;\n if (!realtime && !(_this.startOn || _this.sendOn || _this.sendOnError)) {\n return f => f;\n }\n const maxAge = options.maxAge || 30;\n return next => {\n return (reducer, initialState) => {\n _this.store = (0, _configureStore.default)(\n next,\n _this.monitorReducer,\n {\n maxAge,\n trace: options.trace,\n traceLimit: options.traceLimit,\n shouldCatchErrors: !!_this.sendOnError,\n shouldHotReload: options.shouldHotReload,\n shouldRecordChanges: options.shouldRecordChanges,\n shouldStartLocked: options.shouldStartLocked,\n pauseActionType: options.pauseActionType || \'@@Paused\',\n },\n )(reducer, initialState);\n if (realtime) {\n _this.start();\n }\n _this.store.subscribe(() => {\n if (_this.isMonitored) {\n _this.handleChange(\n _this.store.getState(),\n _this.getLiftedStateRaw(),\n maxAge,\n );\n }\n });\n return _this.store;\n };\n };\n });\n }\n getLiftedStateRaw() {\n return this.store.liftedStore.getState();\n }\n getLiftedState() {\n return (0, _utils.filterStagedActions)(\n this.getLiftedStateRaw(),\n this.filters,\n );\n }\n relay(type, state, action, nextActionId) {\n const message = {\n type,\n\n id: this.socket.id,\n name: this.instanceName,\n instanceId: this.appInstanceId,\n };\n if (state) {\n message.payload =\n type === \'ERROR\'\n ? state\n : (0, _jsan.stringify)(\n (0, _utils.filterState)(\n state,\n type,\n this.filters,\n this.stateSanitizer,\n this.actionSanitizer,\n nextActionId,\n ),\n );\n }\n if (type === \'ACTION\') {\n message.action = (0, _jsan.stringify)(\n !this.actionSanitizer\n ? action\n : this.actionSanitizer(action.action, nextActionId - 1),\n );\n message.isExcess = this.isExcess;\n message.nextActionId = nextActionId;\n } else if (action) {\n message.action = action;\n }\n\n void this.socket.transmit(this.socket.id ? \'log\' : \'log-noid\', message);\n }\n dispatchRemotely(action) {\n try {\n const result = (0, _utils.evalAction)(action, this.actionCreators);\n this.store.dispatch(result);\n } catch (e) {\n this.relay(\'ERROR\', e.message);\n }\n }\n init(options) {\n this.instanceName = options.name;\n this.appInstanceId = getRandomId();\n const {blacklist, whitelist, denylist, allowlist} = options.filters || {};\n this.filters = (0, _utils.getLocalFilter)({\n actionsDenylist:\n denylist ??\n options.actionsDenylist ??\n blacklist ??\n options.actionsBlacklist,\n actionsAllowlist:\n allowlist ??\n options.actionsAllowlist ??\n whitelist ??\n options.actionsWhitelist,\n });\n if (options.port) {\n this.socketOptions = {\n port: options.port,\n hostname: options.hostname || \'localhost\',\n secure: options.secure,\n };\n } else {\n this.socketOptions = _constants.defaultSocketOptions;\n }\n this.suppressConnectErrors =\n options.suppressConnectErrors !== undefined\n ? options.suppressConnectErrors\n : true;\n this.startOn = str2array(options.startOn);\n this.stopOn = str2array(options.stopOn);\n this.sendOn = str2array(options.sendOn);\n this.sendOnError = options.sendOnError;\n if (this.sendOn || this.sendOnError) {\n this.sendTo =\n options.sendTo ||\n `${this.socketOptions.secure ? \'https\' : \'http\'}://${\n this.socketOptions.hostname\n }:${this.socketOptions.port}`;\n this.instanceId = options.id;\n }\n if (this.sendOnError === 1) {\n (0, _utils.catchErrors)(this.sendError);\n }\n if (options.actionCreators) {\n this.actionCreators = () =>\n (0, _utils.getActionsArray)(options.actionCreators);\n }\n this.stateSanitizer = options.stateSanitizer;\n this.actionSanitizer = options.actionSanitizer;\n }\n login() {\n void (async () => {\n try {\n const channelName = await this.socket.invoke(\'login\', \'master\');\n this.channel = channelName;\n let consumer = this.socket.subscribe(channelName).createConsumer();\n while (true) {\n const {value: data, done} = await consumer.next();\n if (done) {\n break;\n }\n\n // for await (const data of this.socket.subscribe(channelName)) {\n this.handleMessages(data);\n }\n } catch (error) {\n console.log(error);\n }\n })();\n this.started = true;\n this.relay(\'START\');\n }\n\n handleChange(state, liftedState, maxAge) {\n if (this.checkForReducerErrors(liftedState)) {\n return;\n }\n if (this.lastAction === \'PERFORM_ACTION\') {\n const nextActionId = liftedState.nextActionId;\n const liftedAction = liftedState.actionsById[nextActionId - 1];\n if ((0, _utils.isFiltered)(liftedAction.action, this.filters)) {\n return;\n }\n this.relay(\'ACTION\', state, liftedAction, nextActionId);\n if (!this.isExcess && maxAge) {\n this.isExcess = liftedState.stagedActionIds.length >= maxAge;\n }\n } else {\n if (this.lastAction === \'JUMP_TO_STATE\') {\n return;\n }\n if (this.lastAction === \'PAUSE_RECORDING\') {\n this.paused = liftedState.isPaused;\n } else if (this.lastAction === \'LOCK_CHANGES\') {\n this.locked = liftedState.isLocked;\n }\n if (this.paused || this.locked) {\n if (this.lastAction) {\n this.lastAction = undefined;\n } else {\n return;\n }\n }\n this.relay(\n \'STATE\',\n (0, _utils.filterStagedActions)(liftedState, this.filters),\n );\n }\n }\n}\nvar _default = options => new DevToolsEnhancer().enhance(options);\nexports.default = _default;\nconst compose = options =>\n function () {\n for (\n var _len = arguments.length, funcs = new Array(_len), _key = 0;\n _key < _len;\n _key++\n ) {\n funcs[_key] = arguments[_key];\n }\n return function () {\n const devToolsEnhancer = new DevToolsEnhancer();\n function preEnhancer(createStore) {\n return (reducer, preloadedState) => {\n devToolsEnhancer.store = createStore(reducer, preloadedState);\n return {\n ...devToolsEnhancer.store,\n dispatch: action =>\n devToolsEnhancer.locked\n ? action\n : devToolsEnhancer.store.dispatch(action),\n };\n };\n }\n for (\n var _len2 = arguments.length, args = new Array(_len2), _key2 = 0;\n _key2 < _len2;\n _key2++\n ) {\n args[_key2] = arguments[_key2];\n }\n return [preEnhancer, ...funcs].reduceRight(\n (composed, f) => f(composed),\n devToolsEnhancer.enhance(options)(...args),\n );\n };\n };\nfunction composeWithDevTools() {\n for (\n var _len3 = arguments.length, funcs = new Array(_len3), _key3 = 0;\n _key3 < _len3;\n _key3++\n ) {\n funcs[_key3] = arguments[_key3];\n }\n if (funcs.length === 0) {\n return new DevToolsEnhancer().enhance();\n }\n if (funcs.length === 1 && typeof funcs[0] === \'object\') {\n return compose(funcs[0]);\n }\n return compose({})(...funcs);\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2451 次 |
| 最近记录: |