react-native-reanimated:onChange 不是函数
react-native-reanimated: onChange is not a function
我遇到 react-native-reanimated 问题:
import Animated from 'react-native-reanimated';
console.log(Animated.onChange) // returns undefined
我正在使用 https://reactnavigation.org/docs/material-top-tab-navigator/ 并在 运行 我的应用程序时收到以下错误:
TypeError: onChange is not a function. (In 'onChange(_this.gesturesEnabled, cond(not(_this.gesturesEnabled), call([_this.gesturesEnabled], _this.toggleEnabled)))', 'onChange' is undefined)
This error is located at:
in Pager (created by TabView)
in RCTView (at View.js:34)
in View (created by TabView)
in TabView (at MaterialTopTabView.tsx:51)
in MaterialTopTabView (at createMaterialTopTabNavigator.tsx:44)
in MaterialTopTabNavigator (at Screen/index.tsx:21)
库本身没有问题(我可以看到库将 onChange 方法正确导出为 Animated 命名空间的一部分),但是我感觉我的反应本机项目的 metro 配置有问题(或 typescript 或 babel 配置,我有点迷路了)。老实说,我不是 metro 或 babel 方面的专家,所以非常感谢任何提示。
package.json
{
"name": "project",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"test": "jest --runInBand --detectOpenHandles",
},
"dependencies": {
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/geolocation": "^2.0.2",
"@react-native-community/masked-view": "^0.1.10",
"@react-native-firebase/analytics": "^8.0.1",
"@react-native-firebase/app": "^9.0.0",
"@react-native-firebase/auth": "^9.3.5",
"@react-native-firebase/crashlytics": "^8.5.2",
"@react-native-firebase/messaging": "^8.0.1",
"@react-native-firebase/perf": "^7.4.12",
"@react-navigation/material-bottom-tabs": "^5.3.9",
"@react-navigation/material-top-tabs": "^5.3.9",
"@react-navigation/native": "^5.8.9",
"@react-navigation/stack": "^5.12.6",
"@welldone-software/why-did-you-render": "^6.0.0-rc.1",
"axios": "^0.21.0",
"babel-plugin-wildcard": "^6.0.0",
"color": "^3.1.3",
"deepmerge": "^4.2.2",
"equentry-frontend-shared": "^2.0.3",
"i18next": "^19.8.3",
"lodash": "^4.17.20",
"metro-config": "^0.64.0",
"react": "17.0.1",
"react-i18next": "^11.7.3",
"react-native": "0.63.3",
"react-native-gesture-handler": "^1.8.0",
"react-native-localize": "^2.0.0",
"react-native-maps": "^0.27.1",
"react-native-paper": "^4.4.0",
"react-native-reanimated": "^1.13.1",
"react-native-safe-area-context": "^3.1.9",
"react-native-screens": "^2.14.0",
"react-native-svg": "^12.1.0",
"react-native-swipe-gestures": "^1.0.5",
"react-native-tab-view": "^2.15.2",
"react-native-vector-icons": "^7.1.0",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3"
},
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"@testing-library/dom": "^7.26.6",
"@testing-library/react-hooks": "^3.4.2",
"@testing-library/react-native": "^7.1.0",
"@testing-library/user-event": "^12.2.2",
"@types/color": "^3.0.1",
"@types/jest": "^26.0.15",
"@types/lodash": "^4.14.165",
"@types/react": "^16.9.56",
"@types/react-native": "^0.63.35",
"@types/react-native-vector-icons": "^6.4.6",
"@types/react-redux": "^7.1.11",
"@types/react-test-renderer": "^16.9.3",
"babel-jest": "^26.6.3",
"babel-plugin-i18next-extract": "^0.8.2",
"detox": "^17.11.4",
"eslint": "^7.13.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"git-branch-is": "^4.0.0",
"husky": "^4.3.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"jest-circus": "^26.6.3",
"jest-junit": "^12.0.0",
"jscpd": "^3.3.19",
"madge": "^3.12.0",
"metro-react-native-babel-preset": "^0.64.0",
"react-native-bundle-visualizer": "^2.2.1",
"react-native-svg-transformer": "^0.14.3",
"react-test-renderer": "17.0.1",
"typedoc": "^0.19.2",
"typedoc-plugin-external-module-name": "^4.0.3",
"typescript": "^4.0.5"
}
}
metro.config.js(我在我的项目中使用了 react-native-svg-transformer):
const { getDefaultConfig } = require('metro-config');
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts },
} = await getDefaultConfig();
return {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
};
})();
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["es6"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext",
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"alwaysStrict": true,
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js",
"jest.setup.js",
"i18n"
]
}
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'i18next-extract',
{
locales: ['en', 'de'],
defaultNS: 'default',
customUseTranslationHooks: [['./src/hooks', 'useTranslation']],
outputPath: './i18n/translations/{{locale}}/{{ns}}.json',
defaultValue: '<translate me>',
useI18nextDefaultValue: true,
},
],
[
'wildcard',
{
exts: ['json', ''],
nostrip: true,
noModifyCase: true,
},
],
],
};
非常感谢任何提示,这让我很头疼。 :x
谢谢!
好的,我通过比较一个只安装了 react-native-reanimated 的新 React Native 应用程序和我的原始项目来弄明白了。
不出所料,问题出在 babel 配置上,尤其是通配符插件。我无法完全弄清楚原因,但是将插件应用于整个项目会产生一些副作用,即我的 node_modules 中的 import * as abc from './somelocation
没有得到正确处理。
因为我只需要将通配符插件应用于特定文件夹./src/i18n/*
,所以我将 babel.config.js
更改如下:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'i18next-extract',
{
locales: ['en', 'de'],
defaultNS: 'default',
customUseTranslationHooks: [['./src/hooks', 'useTranslation']],
outputPath: './src/i18n/translations/{{locale}}/{{ns}}.json',
defaultValue: '<translate me>',
useI18nextDefaultValue: true,
},
],
],
overrides: [
{
test: './src/i18n/*',
plugins: [
[
'wildcard',
{
exts: ['json', ''],
nostrip: true,
noModifyCase: true,
},
],
],
},
],
};
我遇到 react-native-reanimated 问题:
import Animated from 'react-native-reanimated';
console.log(Animated.onChange) // returns undefined
我正在使用 https://reactnavigation.org/docs/material-top-tab-navigator/ 并在 运行 我的应用程序时收到以下错误:
TypeError: onChange is not a function. (In 'onChange(_this.gesturesEnabled, cond(not(_this.gesturesEnabled), call([_this.gesturesEnabled], _this.toggleEnabled)))', 'onChange' is undefined)
This error is located at:
in Pager (created by TabView)
in RCTView (at View.js:34)
in View (created by TabView)
in TabView (at MaterialTopTabView.tsx:51)
in MaterialTopTabView (at createMaterialTopTabNavigator.tsx:44)
in MaterialTopTabNavigator (at Screen/index.tsx:21)
库本身没有问题(我可以看到库将 onChange 方法正确导出为 Animated 命名空间的一部分),但是我感觉我的反应本机项目的 metro 配置有问题(或 typescript 或 babel 配置,我有点迷路了)。老实说,我不是 metro 或 babel 方面的专家,所以非常感谢任何提示。
package.json
{
"name": "project",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"test": "jest --runInBand --detectOpenHandles",
},
"dependencies": {
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/geolocation": "^2.0.2",
"@react-native-community/masked-view": "^0.1.10",
"@react-native-firebase/analytics": "^8.0.1",
"@react-native-firebase/app": "^9.0.0",
"@react-native-firebase/auth": "^9.3.5",
"@react-native-firebase/crashlytics": "^8.5.2",
"@react-native-firebase/messaging": "^8.0.1",
"@react-native-firebase/perf": "^7.4.12",
"@react-navigation/material-bottom-tabs": "^5.3.9",
"@react-navigation/material-top-tabs": "^5.3.9",
"@react-navigation/native": "^5.8.9",
"@react-navigation/stack": "^5.12.6",
"@welldone-software/why-did-you-render": "^6.0.0-rc.1",
"axios": "^0.21.0",
"babel-plugin-wildcard": "^6.0.0",
"color": "^3.1.3",
"deepmerge": "^4.2.2",
"equentry-frontend-shared": "^2.0.3",
"i18next": "^19.8.3",
"lodash": "^4.17.20",
"metro-config": "^0.64.0",
"react": "17.0.1",
"react-i18next": "^11.7.3",
"react-native": "0.63.3",
"react-native-gesture-handler": "^1.8.0",
"react-native-localize": "^2.0.0",
"react-native-maps": "^0.27.1",
"react-native-paper": "^4.4.0",
"react-native-reanimated": "^1.13.1",
"react-native-safe-area-context": "^3.1.9",
"react-native-screens": "^2.14.0",
"react-native-svg": "^12.1.0",
"react-native-swipe-gestures": "^1.0.5",
"react-native-tab-view": "^2.15.2",
"react-native-vector-icons": "^7.1.0",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3"
},
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"@testing-library/dom": "^7.26.6",
"@testing-library/react-hooks": "^3.4.2",
"@testing-library/react-native": "^7.1.0",
"@testing-library/user-event": "^12.2.2",
"@types/color": "^3.0.1",
"@types/jest": "^26.0.15",
"@types/lodash": "^4.14.165",
"@types/react": "^16.9.56",
"@types/react-native": "^0.63.35",
"@types/react-native-vector-icons": "^6.4.6",
"@types/react-redux": "^7.1.11",
"@types/react-test-renderer": "^16.9.3",
"babel-jest": "^26.6.3",
"babel-plugin-i18next-extract": "^0.8.2",
"detox": "^17.11.4",
"eslint": "^7.13.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"git-branch-is": "^4.0.0",
"husky": "^4.3.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"jest-circus": "^26.6.3",
"jest-junit": "^12.0.0",
"jscpd": "^3.3.19",
"madge": "^3.12.0",
"metro-react-native-babel-preset": "^0.64.0",
"react-native-bundle-visualizer": "^2.2.1",
"react-native-svg-transformer": "^0.14.3",
"react-test-renderer": "17.0.1",
"typedoc": "^0.19.2",
"typedoc-plugin-external-module-name": "^4.0.3",
"typescript": "^4.0.5"
}
}
metro.config.js(我在我的项目中使用了 react-native-svg-transformer):
const { getDefaultConfig } = require('metro-config');
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts },
} = await getDefaultConfig();
return {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
};
})();
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["es6"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext",
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"alwaysStrict": true,
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js",
"jest.setup.js",
"i18n"
]
}
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'i18next-extract',
{
locales: ['en', 'de'],
defaultNS: 'default',
customUseTranslationHooks: [['./src/hooks', 'useTranslation']],
outputPath: './i18n/translations/{{locale}}/{{ns}}.json',
defaultValue: '<translate me>',
useI18nextDefaultValue: true,
},
],
[
'wildcard',
{
exts: ['json', ''],
nostrip: true,
noModifyCase: true,
},
],
],
};
非常感谢任何提示,这让我很头疼。 :x
谢谢!
好的,我通过比较一个只安装了 react-native-reanimated 的新 React Native 应用程序和我的原始项目来弄明白了。
不出所料,问题出在 babel 配置上,尤其是通配符插件。我无法完全弄清楚原因,但是将插件应用于整个项目会产生一些副作用,即我的 node_modules 中的 import * as abc from './somelocation
没有得到正确处理。
因为我只需要将通配符插件应用于特定文件夹./src/i18n/*
,所以我将 babel.config.js
更改如下:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'i18next-extract',
{
locales: ['en', 'de'],
defaultNS: 'default',
customUseTranslationHooks: [['./src/hooks', 'useTranslation']],
outputPath: './src/i18n/translations/{{locale}}/{{ns}}.json',
defaultValue: '<translate me>',
useI18nextDefaultValue: true,
},
],
],
overrides: [
{
test: './src/i18n/*',
plugins: [
[
'wildcard',
{
exts: ['json', ''],
nostrip: true,
noModifyCase: true,
},
],
],
},
],
};