clear all form input box after submit form using reactjs - reactjs

want to clear all input box form after submit data
here is my code:
function GSetup() {
const [gName, setGName] = useState("");
const dispatch = useDispatch();
useEffect(() => {
dispatch(getGNames());
}, [dispatch]);
const onSubmitHandler = (e) => {
e.preventDefault();
dispatch(
addGName(
{
gn_name: gName,
su_id: userInfo._id
}
)
);
};
return ( ​);
}
I use this setState on onSubmitHandler function but its not working
this.setState({
gn_name: ''
});

try this way
function GSetup() {
const [gName, setGName] = useState("");
const dispatch = useDispatch();
useEffect(() => {
dispatch(getGNames());
}, [dispatch]);
const onSubmitHandler = (e) => {
e.preventDefault();
dispatch(
addGName(
{
gn_name: gName,
su_id: userInfo._id
}
)
);
setGName('')
};
return ( ​);
}
this.setState({}) does not work outside of classComponent

Related

Stop invoking custom hook on first render

I started having fun with custom hooks recently. I am mostly using them to fetch from api. The thing is that since I cannot really put useFetchLink inside of functions or useEffect i dont know how to prevent it from fetching after website first render. I could put some ifs in the hook but isn't there any other way?
***component***
export default function LinkShortener({ setLinkArr }) {
const [nextLink, setNextLink] = useState();
const inputRef = useRef(null);
const handleClick = () => {
setNextLink(inputRef.current.value);
};
const { shortLink, loading, error } = useFetchLink(nextLink);
useEffect(() => {
setLinkArr((prev) => [
...prev,
{
id: prev.length === 0 ? 1 : prev[prev.length - 1].id + 1,
long: nextLink,
short: shortLink,
},
]);
inputRef.current.value = "";
}, [shortLink, error]);
return (
<LinkShortenerContainer>
<InputContainer>
<LinkInput ref={inputRef} type="text" />
</InputContainer>
<Button
size={buttonSize.medium}
text={
loading ? (
<Loader />
) : (
<FormattedMessage
id="linkShortener.shortenItBtn"
defaultMessage="Shorten It !"
/>
)
}
onClick={handleClick}
></Button>
</LinkShortenerContainer>
);
}
***hook***
const useFetchLink = (linkToShorten) => {
const [shortLink, setShortLink] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const fetchLink = async () => {
setLoading(true);
try {
const response = await fetch(
`https://api.shrtco.de/v2/shorten?url=${linkToShorten}`
);
if (response.ok) {
const data = await response.json();
setShortLink(data.result.short_link);
} else {
throw response.status;
}
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchLink(linkToShorten);
}, [linkToShorten]);
const value = { shortLink, loading, error };
return value;
};```
Why not using directly fetchLink function and calling it whenever you need inside the component? I would change the hook in this way without useEffect inside
const useFetchLink = (linkToShorten) => {
const [shortLink, setShortLink] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const fetchLink = async () => {
setLoading(true);
try {
const response = await fetch(
`https://api.shrtco.de/v2/shorten?url=${linkToShorten}`
);
if (response.ok) {
const data = await response.json();
setShortLink(data.result.short_link);
} else {
throw response.status;
}
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
const value = { shortLink, loading, error, fetchLink };
return value;
};
Generally speaking - the standard way to avoid useEffect from running of 1st render is to use a boolean ref initialized with false, and toggled to true after first render - see this answer.
However, in your case, you don't want to call the function if linkToShorten is empty, even if it's not the 1st render, so use an if inside useEffect.
const useFetchLink = (linkToShorten) => {
const [shortLink, setShortLink] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const fetchLink = useCallback(async (linkToShorten) => {
setLoading(true);
try {
const response = await fetch(
`https://api.shrtco.de/v2/shorten?url=${linkToShorten}`
);
if (response.ok) {
const data = await response.json();
setShortLink(data.result.short_link);
} else {
throw response.status;
}
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if(linkToShorten) fetchLink(linkToShorten);
}, [fetchLink, linkToShorten]);
const value = { shortLink, loading, error };
return value;
};

user.displayName not showing on react firebase app

const [user, setUser] = useState({});
const [pass, setPass] = useState('')
const [name, setName] = useState('')
const [isLoading, setIsLoading] = useState(true)
const auth = getAuth();
const inputHandler = e => {
setUser(e?.target.value)
}
const passHandler = e => {
setPass(e?.target.value)
}
const nameHandler = e => {
setName(e?.target.value)
}
const toggleLogin = event => {
setIsLogIn(!event.target.checked);
}
const signUpHandler = (e) => {
signUp(user, pass)
.then(result => {
setUserName();
history.push(url)
// console.log(url)
})
.finally(() => {
setIsLoading(false)
})
.catch((error) => {
setError(error.message)
// ..
});
e.preventDefault()
}
const signUp = (user, pass) => {
setIsLoading(true)
return createUserWithEmailAndPassword(auth, user, pass)
}
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user)
// console.log("auth changed",user.email)
} else {
setUser({})
}
setIsLoading(false)
});
}, [auth])
const setUserName = () => {
updateProfile(auth.currentUser, {
displayName: name
});
Before displayName property being updated its redirecting to the route it came from. Is this happening for asynchronous nature?
I'm trying to set the displayName property on the navbar.displayName is getting set but not showing on ui, but showing after when I refresh the page. How can I fix this issue?

"Submit" Button requires two clicks to submit React Js

So I wanted to add "whatsapp" like voice note feature in my app I am working on, where you record the voice note and click the "Send" button to send it. I have added the voice recorder code and its working fine in my Logs, but the problem is that when I press the "Send recording" button it sends an empty file in the chat box, and on pressing the same button the second time it then actually sends the recorded Voice note.
The Recorder code component "useRecorder"
import { useEffect, useState } from "react";
import Conversation_Logs from "../Logs/Conversation_Logs";
const useRecorder = () => {
const [audioURL, setAudioURL] = useState("");
const [audioBlob, setAudioBlob] = useState("");
const [isRecording, setIsRecording] = useState(false);
const [recorder, setRecorder] = useState(null);
useEffect(() => {
// Lazily obtain recorder first time we're recording.
if (recorder === null) {
if (isRecording) {
requestRecorder().then(setRecorder, console.error);
}
return;
}
// Manage recorder state.
if (isRecording) {
recorder.start();
} else {
recorder.stop();
}
// Obtain the audio when ready.
const handleData = e => {
setAudioURL(URL.createObjectURL(e.data));
let wavfromblob = new File([e.data], "incomingaudioclip.wav")
setAudioBlob(wavfromblob);
};
recorder.addEventListener("dataavailable", handleData);
return () => recorder.removeEventListener("dataavailable", handleData);
}, [recorder, isRecording]);
const startRecording = () => {
setIsRecording(true);
};
const stopRecording = () => {
setIsRecording(false);
};
return [audioURL,audioBlob, isRecording, startRecording, stopRecording];
};
async function requestRecorder() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
return new MediaRecorder(stream);
}
export default useRecorder;
The Code where send recording button is called component named "RecorderBox
import React, {useState,useEffect} from "react";
import { render } from "react-dom";
import useRecorder from "./useRecorder";
const RecorderBox = (props) =>{
const { log, handleUpdateLog,handleSubmitNewMessage ,selectedLog} = props
let [audioURL,audioBlob, isRecording, startRecording, stopRecording] = useRecorder();
const [ newMessage, setNewMessage ] = useState("");
const [ attachFile, setAttachFile ] = useState();
const submitNewMessage = () => {
setAttachFile(audioBlob)
const body = {
body: newMessage,
attachment: attachFile
}
handleUpdateLog(log,newMessage, attachFile)
console.log(attachFile)
// handleSubmitNewMessage(log.id,body)
}
useEffect(() => {
setNewMessage("")
setAttachFile(null)
!!document.getElementsByClassName("dzu-previewButton")[0] && document.getElementsByClassName("dzu-previewButton")[0].click()
}, [log])
return (
<div className="RecorderBox">
<audio src={audioURL} controls />
<button onClick={startRecording} disabled={isRecording}>
start recording
</button>
<button onClick={() => {
stopRecording();
}} disabled={!isRecording}>
stop recording
</button>
<button onClick={() => {
submitNewMessage();
}}>
send recording
</button>
<p>
<em>
</em>
</p>
</div>
);
}
export default RecorderBox;
TL;DR: submitNewMessage is running in the scope of the previous render, thus attachFile doesn't contain anything yet. Whatever audio you managed to send on the second click was actually the first recording you tried to send.
Solution: Skip attachFile completely.
A couple of hints: Don't have a useEffect depend on a state that the effect itself is updating, and dont use a useEffect for doing something that a click-handler can do.
Here's a safer version of your code. I haven't tested it, but any bugs should be easy to fix.
import { useCallback, useEffect, useRef, useState } from 'react';
// This is a nugget I use in many similar cases.
/**
* Similar to `useMemo`, but accepts a callback that return a promise.
* Very useful when working with states that depend on some async function.
*
* #link https://gist.github.com/mariusbrataas/ffca05c210ec540b4fb9f4324c4f2e68
*
* #example
* function MyComponent({url}:{url: string}) {
* const data = usePromiseMemo(
* () =>
* fetch(url)
* .then(r => r.json())
* .then(r => r.my.user.info),
* [url]
* );
*
* return <p>{info || "Loading info..."}</p>
* }
*/
export function usePromiseMemo<T>(
callback: () => Promise<T> | T,
deps?: any[]
) {
// Private states
const [state, setState] = useState<T>();
const isMounted = useRef(true);
// Register unmount
useEffect(() => {
if (!isMounted.current) isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
// Execute callback
useEffect(() => {
if (isMounted.current) {
if (state !== undefined) setState(undefined);
Promise.resolve()
.then(() => callback())
.then(r => {
if (isMounted.current) setState(r);
});
}
}, deps || []);
// Return state
return state;
}
function useRecorder() {
const [audioURL, setAudioURL] = useState<string>();
const [audioBlob, setAudioBlob] = useState<File>();
const [isRecording, setIsRecording] = useState(false);
// Handler for recorded data
const handleRecorderData = useCallback(
(e: BlobEvent) => {
setAudioURL(URL.createObjectURL(e.data));
setAudioBlob(new File([e.data], 'incomingaudioclip.wav'));
},
[setAudioURL, setAudioBlob]
);
// Create recorder
const recorder = usePromiseMemo(
() =>
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(stream => new MediaRecorder(stream)),
[]
);
// Attach event listener
useEffect(() => {
if (recorder)
recorder.addEventListener('dataavailable', handleRecorderData);
return () => {
if (recorder)
recorder.removeEventListener('dataavailable', handleRecorderData);
};
}, [recorder, handleRecorderData]);
// Handle start recording
const startRecording = useCallback(() => {
if (recorder) {
recorder.start();
setIsRecording(true);
}
}, [recorder, setIsRecording]);
// Handle stop recording
const stopRecording = useCallback(() => {
if (recorder) {
recorder.stop();
setIsRecording(false);
}
}, [recorder, setIsRecording]);
// Return
return {
audioURL,
audioBlob,
setAudioBlob,
isRecording,
startRecording,
stopRecording
};
}
export const RecorderBox = ({
log,
handleUpdateLog,
handleSubmitNewMessage,
selectedLog
}: any) => {
const {
audioURL,
audioBlob,
setAudioBlob,
isRecording,
startRecording,
stopRecording
} = useRecorder();
const [newMessage, setNewMessage] = useState('');
// Create a decorated submit function
const decoratedSubmitNewMessage = useCallback(() => {
const body = {
body: newMessage,
attachment: audioBlob
};
handleUpdateLog(log, newMessage, audioBlob);
// handleSubmitNewMessage(log.id, body); // You had this commented out, but it should work just fine.
}, [handleUpdateLog, handleSubmitNewMessage, audioBlob, newMessage]);
// Cleanup whenever receiving new object for `log`
useEffect(() => {
setNewMessage('');
setAudioBlob(undefined);
document.getElementsByClassName('dzu-previewButton')[0]?.click(); // No idea what this is supposed to do.
}, [log, setNewMessage, setAudioBlob]);
return (
<div className="RecorderBox">
<audio src={audioURL} controls />
<button onClick={startRecording} disabled={isRecording}>
start recording
</button>
<button onClick={stopRecording} disabled={!isRecording}>
stop recording
</button>
<button onClick={decoratedSubmitNewMessage}>send recording</button>
<p>
<em></em>
</p>
</div>
);
};
JavaScript version:
import { useCallback, useEffect, useRef, useState } from 'react';
// This is a nugget I use in many similar cases.
/**
* Similar to `useMemo`, but accepts a callback that return a promise.
* Very useful when working with states that depend on some async function.
*
* #link https://gist.github.com/mariusbrataas/ffca05c210ec540b4fb9f4324c4f2e68
*
* #example
* function MyComponent({url}:{url: string}) {
* const data = usePromiseMemo(
* () =>
* fetch(url)
* .then(r => r.json())
* .then(r => r.my.user.info),
* [url]
* );
*
* return <p>{info || "Loading info..."}</p>
* }
*/
export function usePromiseMemo(callback, deps) {
// Private states
const [state, setState] = useState();
const isMounted = useRef(true);
// Register unmount
useEffect(() => {
if (!isMounted.current) isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
// Execute callback
useEffect(() => {
if (isMounted.current) {
if (state !== undefined) setState(undefined);
Promise.resolve()
.then(() => callback())
.then(r => {
if (isMounted.current) setState(r);
});
}
}, deps || []);
// Return state
return state;
}
function useRecorder() {
const [audioURL, setAudioURL] = useState();
const [audioBlob, setAudioBlob] = useState();
const [isRecording, setIsRecording] = useState(false);
// Handler for recorded data
const handleRecorderData = useCallback(
e => {
setAudioURL(URL.createObjectURL(e.data));
setAudioBlob(new File([e.data], 'incomingaudioclip.wav'));
},
[setAudioURL, setAudioBlob]
);
// Create recorder
const recorder = usePromiseMemo(
() =>
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(stream => new MediaRecorder(stream)),
[]
);
// Attach event listener
useEffect(() => {
if (recorder)
recorder.addEventListener('dataavailable', handleRecorderData);
return () => {
if (recorder)
recorder.removeEventListener('dataavailable', handleRecorderData);
};
}, [recorder, handleRecorderData]);
// Handle start recording
const startRecording = useCallback(() => {
if (recorder) {
recorder.start();
setIsRecording(true);
}
}, [recorder, setIsRecording]);
// Handle stop recording
const stopRecording = useCallback(() => {
if (recorder) {
recorder.stop();
setIsRecording(false);
}
}, [recorder, setIsRecording]);
// Return
return {
audioURL,
audioBlob,
setAudioBlob,
isRecording,
startRecording,
stopRecording
};
}
export const RecorderBox = ({
log,
handleUpdateLog,
handleSubmitNewMessage,
selectedLog
}) => {
const {
audioURL,
audioBlob,
setAudioBlob,
isRecording,
startRecording,
stopRecording
} = useRecorder();
const [newMessage, setNewMessage] = useState('');
// Create a decorated submit function
const decoratedSubmitNewMessage = useCallback(() => {
const body = {
body: newMessage,
attachment: audioBlob
};
handleUpdateLog(log, newMessage, audioBlob);
// handleSubmitNewMessage(log.id, body); // You had this commented out, but it should work just fine.
}, [handleUpdateLog, handleSubmitNewMessage, audioBlob, newMessage]);
// Cleanup whenever receiving new object for `log`
useEffect(() => {
setNewMessage('');
setAudioBlob(undefined);
document.getElementsByClassName('dzu-previewButton')[0]?.click(); // No idea what this is supposed to do.
}, [log, setNewMessage, setAudioBlob]);
return (
<div className="RecorderBox">
<audio src={audioURL} controls />
<button onClick={startRecording} disabled={isRecording}>
start recording
</button>
<button onClick={stopRecording} disabled={!isRecording}>
stop recording
</button>
<button onClick={decoratedSubmitNewMessage}>send recording</button>
<p>
<em></em>
</p>
</div>
);
};

How to get the current state inside socket.io on callback function

const useChat = () => {
const [messages, setMessages] = useState([]);
const socketRef = useRef();
const { chatId } = useSelector(state => state.chatin)
const { chatList } = useSelector(state => state.chatin)
const dispatch = useDispatch()
useEffect(() => {
socketRef.current = io(socketClient);
socketClient.on('chat', (data) => {
const targetMessage = (messages) => messages.findIndex(item => item.message_number === data.message_number);
console.log('targetMessage', targetMessage)
if (targetMessage !== -1) {
messages[targetMessage].is_hide = true;
}
setMessages((messages) => [...messages, data]);
});
return () => {
socketRef.current.disconnect();
};
}, []);
whenever I got new socket data, I wanna change 'messages' data, but can't access it, because it always shows initial data value.After that I have a question about how can I set it?
You can move the if condition inside setMessages function, this way you will get access to the current state:
socketClient.on('chat', (data) => {
setMessages((messages) => {
const targetMessage = messages.findIndex(item => item.message_number === data.message_number);
if (targetMessage !== -1) {
messages[targetMessage].is_hide = true;
}
return [...messages, data]
});
});

Refactor a functional component with React hooks

I have several functional components which share the same logic. So I would like to refactor them using React hooks. All of them make some calls to the server on mount to check if the order has been paid. If yes, paid state is set to true , and a file is being downloaded. On submit I check if paid state is set to true, if yes, the same file is being downloaded, if not, a new order is created and a user is being redirected to a page with a payment form.
I have already extracted all functions (getOrder(), getPaymentState(), createOrder(), initPayment() and downloadFile()) which make API calls to the server. How can I further optimize this code, so that I could move checkOrder(), checkPayment(), downloadPDF() and newOrder() outside the component to use the same logic with other components as well?
Here is my component:
const Form = () => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async values => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async values => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return (
)
}
EDIT 1: I also need to be able to pass some data to this hook: downloadData, sendURL, description, sum and returnURL, which will be different in each case. downloadData then needs to be populated with some data from the values.
I would appreciate if you could point me at the right direction. I'm just learning React and I would really like to find the correct way to do this.
EDIT 2: I've posted my own answer with the working code based on the previous answers. It's not final, because I still need to move downloadPDF() outside the component and pass downloadData to it, but when I do so, I get an error, that values are undefined. If anybody can help me with that, I will accept it as an answer.
I made a quick refactor of the code and put it in a custom hook, it looks like search param is the key for when the effect needs to run.
const useCheckPayment = (search) => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = useCallback(async () => {
let paramSearch = new URLSearchParams(search);
let success = paramSearch.get('Success');
if (success) {
try {
//why not just pass it, makes getOrder a little less impure
const data = await getOrder(paramSearch);
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message);
}
}
}, [checkPayment, search]);
const checkPayment = useCallback(async (values) => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message);
}
}, []);
const downloadPDF = async (values) => {
setLoading(true);
const response = await downloadFile();
setLoading(false);
window.location.assign(response.pdf);
};
const newOrder = async (values) => {
setSubmitting(true);
const order = await createOrder();
const paymentUrl = await initPayment(order);
setSubmitting(false);
window.location.assign(paymentUrl);
};
const onSubmit = useCallback(
async (values) => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values);
} catch (err) {
alert(err.message);
}
}
},
[data, paid]
);
useEffect(() => {
checkOrder();
}, [checkOrder]); //checkOrder will change when search changes and effect is called again
return { onSubmit, submitting, loading };
};
const Form = () => {
const { onSubmit, submitting, loading } = useCheckPayment(
window.location.search
);
return '';
};
You can extract out all the generic things from within the Form component into a custom Hook and return the required values from this hook
The values which are dependencies and will vary according to the component this is being called from can be passed as arguments to the hook. Also the hook can return a onSubmit function to which you can pass on the downloadData
const useOrderHook = ({returnURL, sendURL, }) => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async (values, description, sum) => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async ({values, downloadData: data, description, sum}) => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values, description, sum)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return {onSubmit, loading, submitting, paid, data };
}
Now you can use this hook in component like Form as follows
const Form = () => {
const {onSubmit, newOrder, loading, submitting, paid, data } = useOrderHook({returnUrl: 'someUrl', sendURL: 'Some send URL'})
const handleSubmit = (values) => {
// since this function is called, you can get the values from its closure.
const data = {email: values.email, phone: values.phone}
onSubmit({ data, values, description, sum})// pass in the required values for onSubmit here. you can do the same when you actually call newOrder from somewhere
}
// this is how you pass on handleSubmit to React-final-form
return <Form
onSubmit={handleSubmit }
render={({ handleSubmit }) => {
return <form onSubmit={handleSubmit}>...fields go here...</form>
}}
/>
}
Based on the answers above I came up with the following code.
The hook:
const useCheckPayment = ({initialValues, sendUrl, successUrl, description, sum, downloadPDF}) => {
const [paid, setPaid] = useState(false);
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [data, setData] = useState(initialValues);
const checkOrder = useCallback(
async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get('Success');
if (success) {
try {
const data = await getOrder(search);
setData(data);
checkPayment(search);
} catch (err) {
alert(err.message);
}
}
}, [checkPayment]
);
const checkPayment = useCallback(
async (search) => {
try {
const paid = await getPaymentState(search);
setPaid(paid);
document.getElementById('myForm').dispatchEvent(new Event('submit', { cancelable: true }))
} catch (err) {
alert(err.message);
}
}, []
);
const newOrder = useCallback(
async (values) => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, successUrl);
setSubmitting(false);
window.location.assign(paymentUrl);
}, [description, sum, successUrl]
);
const downloadPDF = async (values, downloadData) => {
setLoading(true);
const response = await downloadFile(downloadData, sendUrl);
setLoading(false);
window.location.assign(response.pdf);
};
const onSubmit = useCallback(
async ({ values, downloadData }) => {
if (paid) {
try {
downloadPDF(values, downloadData);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values);
} catch (err) {
alert(err.message);
}
}
},
[paid, downloadPDF, newOrder]
);
useEffect(() => {
checkOrder();
}, [checkOrder]);
return { onSubmit, submitting };
};
The component:
const sendUrl = 'https://app.example.com/send'
const successUrl = 'https://example.com/success'
const description = 'Download PDF file'
const sum = '100'
const Form = () => {
const handleSubmit = (values) => {
const downloadData = {
email: values.email,
phone: values.phone
}
onSubmit({ downloadData, values })
}
const { onSubmit, submitting } = useCheckPayment(
{sendUrl, successUrl, description, sum}
);
return (
<Form
onSubmit={handleSubmit}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}></form>
)}
/>
)
}

Resources