'Null is not an object' 使用自定义 React Native npm 包
'Null is not an object' with a custom React Native npm package
我创建了一个用于短信验证的自定义 npm 包。这是一个 PIN 代码输入,如果您通过 SMS 收到 PIN,它会自动填写。它本身就很好用。当我将 npm 包上传到 Azure Artifacts 并尝试在另一个项目中使用它时出现问题。
配置后.npmrc
到
registry=https://pkgs.dev.azure.com/<url>/npm/registry/
always-auth=true
我用 npx react-native init SMSTest
开始一个新的 React Native 项目,并在新项目中用 npm install
安装包。
当我尝试使用该组件时出现错误 TypeError: null is not an object (evaluating 'RNOtpVerify.getOtp')
并且该应用无法运行。如果我 运行 npm i react-native-otp-verify
.
错误消失
有趣的是,所有依赖项都已经存在于 node_modules
中,甚至在我第二次通过 npm 安装它们之前。
任何想法可能是什么问题以及如何解决它?
App.tsx
import React from 'react';
import {StyleSheet, View} from 'react-native';
import GiSmsVerificationInput from '<company-name>/GiSmsVerificationInput';
interface AppProps {}
const App: React.FC<AppProps> = props => {
return (
<GiSmsVerificationInput
onFulfill={code => console.log(code)}></GiSmsVerificationInput>
);
};
const styles = StyleSheet.create({});
export default App;
GiSmsVerificationInput.tsx
import React, { useState, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import SmoothPinCodeInput from 'react-native-smooth-pincode-input';
import RNOtpVerify from 'react-native-otp-verify';
/**
* @param pinInput (Optional) Properties you want to pass to SmoothPinCodeInput
* @param onFulfill Handler for when the user fills out pin
* @param extractOTP (Optional) Extraction function for the OTP in the SMS
*/
interface SmsVerificationInputProps {
/**
* (Optional) Properties you want to pass to SmoothPinCodeInput
*/
pinInputProps?: any;
/**
* Handler for when the user fills out pin
* @param code PIN code entered
*/
onFulfill: (code: string) => any;
/**
* (Optional) Extraction function for the OTP in the SMS
* @param message Full SMS message received
*/
extractOTP?: (message: string) => string;
}
/**
* Verification PIN input component. Listens to SMS and fills out automatically if the right sms is sent.
*/
const SmsVerificationInput: React.FC<SmsVerificationInputProps> = (props) => {
const [code, setCode] = useState('');
/**
* Function to get the hash that has to be appended to the message for the SMS listener to work.
* Eg. SMS: This is your code: 1234 Uo4J1jaLso7
*/
const getHash = () => {
RNOtpVerify.getHash()
.then((res) => console.log('Use Hash:', res[0]))
.catch((err) => console.log(err));
};
/**
* Start listening for SMS with the hash appended. Not triggered on an received SMS without the hash.
* */
const startListeningForOtp = () => {
RNOtpVerify.getOtp()
.then((p) => {
RNOtpVerify.addListener((message) => {
otpHandler(message);
});
})
.catch((p) => console.log(p));
};
/**
* Handle the received SMS with hash. Restarts listener for any subsequent messages the user might request.
* @param message Full SMS message
*/
const otpHandler = (message: string) => {
if (message && !message.includes('Error')) {
console.log('otpHandler', message);
console.log('set pin to:', extractOTP(message));
setCode(extractOTP(message));
}
RNOtpVerify.removeListener();
startListeningForOtp();
};
/**
* Extract code from your SMS message.
* @param message Full SMS message
*/
const extractOTP = (message: string) => {
if (props.extractOTP) {
return props.extractOTP(message);
}
return /(\d{4})/g.exec(message)[1];
};
/**
* Start listening for OTP on first render. Remove listener when component is destroyed.
*/
useEffect(() => {
getHash();
startListeningForOtp();
return RNOtpVerify.removeListener();
}, []);
const DefaultMask = <View style={styles.mask} />;
return (
<SmoothPinCodeInput
value={code}
onTextChange={(code: string) => setCode(code)}
onFulfill={(code: string) => props.onFulfill(code)}
cellStyle={styles.cell}
autoFocus={true}
cellStyleFocused={null}
cellSize={50}
codeLength={4}
cellSpacing={5}
keyboardType={'number-pad'}
maskDelay={500}
password={true}
mask={DefaultMask}
textStyle={styles.text}
{...props.pinInputProps}
/>
);
};
const styles = StyleSheet.create({
cell: {},
text: {},
mask: {},
});
export default SmsVerificationInput;
package.json
"name": "",
"version": "",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [
],
"author": "",
"license": "ISC",
"dependencies": {
"@types/react-native": "^0.63.34",
"react": "16.13.1",
"react-native": "^0.63.3",
"react-native-otp-verify": "^1.0.3",
"react-native-smooth-pincode-input": "^1.0.9",
"react-native-sms-retriever": "^1.1.1"
}
}
您可以尝试删除整个 node_modules 文件夹,并删除 package-lock.json 文件。然后 运行 npm install 再次
如果删除 node_modules 和 package-lock.json 不起作用。您可以尝试将 react-native-otp-verify
依赖项显式添加到项目 SMSTest 的 package.json 文件中。
您也可以尝试将 "preinstall": "npm install react-native-otp-verify"
添加到项目 package.json 文件中的脚本部分。
查看 this thread 了解更多信息。
我创建了一个用于短信验证的自定义 npm 包。这是一个 PIN 代码输入,如果您通过 SMS 收到 PIN,它会自动填写。它本身就很好用。当我将 npm 包上传到 Azure Artifacts 并尝试在另一个项目中使用它时出现问题。
配置后.npmrc
到
registry=https://pkgs.dev.azure.com/<url>/npm/registry/
always-auth=true
我用 npx react-native init SMSTest
开始一个新的 React Native 项目,并在新项目中用 npm install
安装包。
当我尝试使用该组件时出现错误 TypeError: null is not an object (evaluating 'RNOtpVerify.getOtp')
并且该应用无法运行。如果我 运行 npm i react-native-otp-verify
.
有趣的是,所有依赖项都已经存在于 node_modules
中,甚至在我第二次通过 npm 安装它们之前。
任何想法可能是什么问题以及如何解决它?
App.tsx
import React from 'react';
import {StyleSheet, View} from 'react-native';
import GiSmsVerificationInput from '<company-name>/GiSmsVerificationInput';
interface AppProps {}
const App: React.FC<AppProps> = props => {
return (
<GiSmsVerificationInput
onFulfill={code => console.log(code)}></GiSmsVerificationInput>
);
};
const styles = StyleSheet.create({});
export default App;
GiSmsVerificationInput.tsx
import React, { useState, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import SmoothPinCodeInput from 'react-native-smooth-pincode-input';
import RNOtpVerify from 'react-native-otp-verify';
/**
* @param pinInput (Optional) Properties you want to pass to SmoothPinCodeInput
* @param onFulfill Handler for when the user fills out pin
* @param extractOTP (Optional) Extraction function for the OTP in the SMS
*/
interface SmsVerificationInputProps {
/**
* (Optional) Properties you want to pass to SmoothPinCodeInput
*/
pinInputProps?: any;
/**
* Handler for when the user fills out pin
* @param code PIN code entered
*/
onFulfill: (code: string) => any;
/**
* (Optional) Extraction function for the OTP in the SMS
* @param message Full SMS message received
*/
extractOTP?: (message: string) => string;
}
/**
* Verification PIN input component. Listens to SMS and fills out automatically if the right sms is sent.
*/
const SmsVerificationInput: React.FC<SmsVerificationInputProps> = (props) => {
const [code, setCode] = useState('');
/**
* Function to get the hash that has to be appended to the message for the SMS listener to work.
* Eg. SMS: This is your code: 1234 Uo4J1jaLso7
*/
const getHash = () => {
RNOtpVerify.getHash()
.then((res) => console.log('Use Hash:', res[0]))
.catch((err) => console.log(err));
};
/**
* Start listening for SMS with the hash appended. Not triggered on an received SMS without the hash.
* */
const startListeningForOtp = () => {
RNOtpVerify.getOtp()
.then((p) => {
RNOtpVerify.addListener((message) => {
otpHandler(message);
});
})
.catch((p) => console.log(p));
};
/**
* Handle the received SMS with hash. Restarts listener for any subsequent messages the user might request.
* @param message Full SMS message
*/
const otpHandler = (message: string) => {
if (message && !message.includes('Error')) {
console.log('otpHandler', message);
console.log('set pin to:', extractOTP(message));
setCode(extractOTP(message));
}
RNOtpVerify.removeListener();
startListeningForOtp();
};
/**
* Extract code from your SMS message.
* @param message Full SMS message
*/
const extractOTP = (message: string) => {
if (props.extractOTP) {
return props.extractOTP(message);
}
return /(\d{4})/g.exec(message)[1];
};
/**
* Start listening for OTP on first render. Remove listener when component is destroyed.
*/
useEffect(() => {
getHash();
startListeningForOtp();
return RNOtpVerify.removeListener();
}, []);
const DefaultMask = <View style={styles.mask} />;
return (
<SmoothPinCodeInput
value={code}
onTextChange={(code: string) => setCode(code)}
onFulfill={(code: string) => props.onFulfill(code)}
cellStyle={styles.cell}
autoFocus={true}
cellStyleFocused={null}
cellSize={50}
codeLength={4}
cellSpacing={5}
keyboardType={'number-pad'}
maskDelay={500}
password={true}
mask={DefaultMask}
textStyle={styles.text}
{...props.pinInputProps}
/>
);
};
const styles = StyleSheet.create({
cell: {},
text: {},
mask: {},
});
export default SmsVerificationInput;
package.json
"name": "",
"version": "",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [
],
"author": "",
"license": "ISC",
"dependencies": {
"@types/react-native": "^0.63.34",
"react": "16.13.1",
"react-native": "^0.63.3",
"react-native-otp-verify": "^1.0.3",
"react-native-smooth-pincode-input": "^1.0.9",
"react-native-sms-retriever": "^1.1.1"
}
}
您可以尝试删除整个 node_modules 文件夹,并删除 package-lock.json 文件。然后 运行 npm install 再次
如果删除 node_modules 和 package-lock.json 不起作用。您可以尝试将 react-native-otp-verify
依赖项显式添加到项目 SMSTest 的 package.json 文件中。
您也可以尝试将 "preinstall": "npm install react-native-otp-verify"
添加到项目 package.json 文件中的脚本部分。
查看 this thread 了解更多信息。