react-native-recaptcha-that-works
react-native-recaptcha-that-works copied to clipboard
RFC add promise based method to obtain the token
Hello, Thank you for this library 🥇 I would like to propose another interesting feature to this library.
Description
Image the case, when the library is in invisible state and I would like to display the captcha, once user clicked on submit button in the form. When the submission is completed, then we can make an api call to apply the changes. So far I need to handle it using the callback, which is not the cleanest way to do it. Hence I would like to improve it using async/await handle
Posible implementation
Create a ref, which will be responsible for storing the promise
const $promiseToken = useRef<{
resolve: (value: GetToken | PromiseLike<GetToken>) => void;
reject: (arg: any) => void;
} | null>();
Move code to the separate method. It will be used in both places
const onOpen = useCallback(() => {
setVisible(true);
setLoading(true);
$isClosed.current = false;
}, []);
Add new async method getToken, which will be responsible for opening the modal and fetching the token
This promise will be stored in the ref called $promiseToken
useImperativeHandle(
ref,
() => ({
open: () => {
onOpen();
},
close: handleClose,
getToken: () => {
onOpen();
return new Promise<GetToken>(
(resolve, reject: (arg: any) => void) => {
$promiseToken.current = { resolve, reject };
}
);
},
}),
[handleClose, onOpen]
);
Handle this promise in handleMessage
method
const handleMessage = useCallback(
(content) => {
try {
const payload = JSON.parse(content.nativeEvent.data);
if (payload.close) {
if (isInvisibleSize) {
handleClose();
}
}
if (payload.load) {
handleLoad(...payload.load);
}
if (payload.expire) {
//@ts-ignore
onExpire?.(...payload.expire);
}
if (payload.error) {
handleClose();
//@ts-ignore
onError?.(...payload.error);
$promiseToken?.current?.reject(payload.error);
}
if (payload.verify) {
handleClose();
//@ts-ignore
onVerify?.(...payload.verify);
const token = payload?.verify?.[0] || '';
$promiseToken?.current?.resolve({ token: token });
}
} catch (err) {
$promiseToken?.current?.reject(err);
}
},
[onVerify, onExpire, onError, handleClose, handleLoad, isInvisibleSize]
);
After everything, we need to clean up a little bit to avoid memory leak
React.useEffect(() => {
return () => {
$promiseToken.current = null;
};
}, []);
Before
const App = () => {
const size = 'normal';
const [key, setKey] = useState('<none>');
const $recaptcha = useRef();
const handleOpenPress = useCallback(() => {
$recaptcha.current.open();
}, []);
const handleClosePress = useCallback(() => {
$recaptcha.current.close();
}, []);
useState(() => {
// handle submit here (api call), which is not the best solution. I would prefer to have it all at one place
},[key])
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={styles.safeArea}>
<View
contentInsetAdjustmentBehavior="automatic"
style={styles.container}>
<Button onPress={handleOpenPress} title="Open" />
<Text>Token: {key}</Text>
<Text>Size: {size}</Text>
</View>
<Recaptcha
ref={$recaptcha}
lang="en"
headerComponent={<Button title="Close" onPress={handleClosePress} />}
siteKey="6LejsqwZAAAAAGsmSDWH5g09dOyNoGMcanBllKPF"
baseUrl="http://127.0.0.1"
size={size}
theme="light"
onLoad={() => alert('onLoad event')}
onClose={() => alert('onClose event')}
onError={(err) => {
alert('onError event');
console.warn(err);
}}
onExpire={() => alert('onExpire event')}
onVerify={(token) => {
alert('onVerify event');
setKey(token);
}}
/>
</SafeAreaView>
</>
);
};
After
const App = () => {
const size = 'normal';
const [key, setKey] = useState('<none>');
const $recaptcha = useRef();
const handleOpenPress = useCallback(() => {
const response = await $recaptcha?.current?.getToken();
if (response?.token) {
// do some api calls etc
} else {
// do some api calls etc
Alert.alert('Title', 'Something went wrong');
} }, []);
const handleClosePress = useCallback(() => {
$recaptcha.current.close();
}, []);
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={styles.safeArea}>
<View
contentInsetAdjustmentBehavior="automatic"
style={styles.container}>
<Button onPress={handleOpenPress} title="Open" />
<Text>Token: {key}</Text>
<Text>Size: {size}</Text>
</View>
<Recaptcha
ref={$recaptcha}
lang="en"
headerComponent={<Button title="Close" onPress={handleClosePress} />}
siteKey="6LejsqwZAAAAAGsmSDWH5g09dOyNoGMcanBllKPF"
baseUrl="http://127.0.0.1"
size={size}
theme="light"
onLoad={() => alert('onLoad event')}
onClose={() => alert('onClose event')}
onError={(err) => {
alert('onError event');
console.warn(err);
}}
onExpire={() => alert('onExpire event')}
onVerify={(token) => {
alert('onVerify event');
setKey(token);
}}
/>
</SafeAreaView>
</>
);
};
WDYT about above approach ? Feel free to comment.
~~I don't know why, github didn't notify me of your message.~~
Hi @troZee, thanks for the suggestions.
I already had this change in mind, but at the moment I don't have time to put it into practice.
If you are interested in creating a pull request, I will be happy to review it.
I would just add error handling with promise.reject to your suggestion.
~~I don't know why, github didn't notify me of your message.~~
Hi @troZee, thanks for the suggestions.
I already had this change in mind, but at the moment I don't have time to put it into practice.
If you are interested in creating a pull request, I will be happy to rate it.
I would just add error handling with promise.reject to your suggestion.
Sure, I will prepare a PR for it, bc i added this additional code as a pack package. In prepared PR, we will discuss about it
@troZee Whatever happened to the PR?