#javascript #reactjs #next.js #formik
#javascript #reactjs #next.js #formik
Вопрос:
Я использую Formik в своем Next.js приложение, и я столкнулся с проблемой, которую я не уверен, как исправить. Моя отправка Button
— это компонент, который принимает showSpinner
prop. Если значение true -> кнопка отключена и отображается счетчик загрузки в кнопке. showSpinner
значение зависит от loading
того, что поступает из useState
перехвата. Вот соответствующий код:
export default function register() {
const [loading, setLoading] = useState(false)
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: '',
password: '',
passwordConfirm: '',
acceptedTerms: false
}}
onSubmit={
(values, { setSubmitting }) => {
console.log(loading)
// here loading == false as expected
setLoading(true)
console.log(loading)
// here loading == false even though i set it to true
initFirebase()
firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
.then((res) => {
console.log('done!')
})
.catch(function (error) {
// Handle Errors here.
console.log(error)
})
.finally(() => {
console.log(loading)
//here loading == false too, even though I expected it to be true
setSubmitting(false)
setLoading(false)
})
}
}
>
<Form>
<FormikText label="Email:"
name="email"
type="email"
id="email" />
<FormikPassword label="Password:"
name="password"
id="password"
/>
<FormikPassword label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox
name="acceptedTerms"
id="acceptedTerms"
>
<span className={styles.checkboxLabel}>
I agree to the <Link href="/terms" ><a className={styles.registerLink}>Terms of Service</a></Link> and <Link href="/privacy"><a className={styles.registerLink}>Privacy/Cookie Policy</a></Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button type="submit" color="blue" showSpinner={loading}>Sign Up</Button>
</div>
</Form>
</Formik>
</div>
</div>
</Layout>
</>
)
}
Несмотря на то, что мой Button
каким-то образом работает так, как ожидалось (счетчик отображается как задумано), после console.loging
значения loading
через onSubmit
вызов функции я заметил, что это false
если бы я ожидал, что это будет правдой. Это связано с тем, как реагируют пакеты useState
вызовов?
Мои вопросы:
- Как правильно обработать этот сценарий?
- Если
loading == false
в нихconsole.logs
, почему мойButton
работает так, как задумано?
Комментарии:
1. Я бы начал с проверки того, что setLoading() вычисляет в функции onSubmit. Вы можете определить фиктивную функцию и посмотреть, правильно ли она запускается в onSubmit.
Ответ №1:
связано ли это с тем, как пакеты React используют вызовы useState?
Я думаю, что да, именно поэтому Formik
предоставляет isSubmitting
флаг, попробуйте использовать его вместо отслеживания вашего собственного loading
состояния, я знаю, что это работает для ваших текущих спецификаций, но у вас могут возникнуть некоторые проблемы, когда этот компонент становится более сложным
Ваш код будет выглядеть следующим образом
export default function register() {
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: "",
password: "",
passwordConfirm: "",
acceptedTerms: false,
}}
onSubmit={async (values) => {
try {
initFirebase();
await firebase
.auth()
.createUserWithEmailAndPassword(
values.email,
values.password
);
} catch (e) {
// Handle Errors here.
console.log(error);
}
}}
>
{({ isSubmitting }) => (
<Form>
<FormikText
label="Email:"
name="email"
type="email"
id="email"
/>
<FormikPassword
label="Password:"
name="password"
id="password"
/>
<FormikPassword
label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox name="acceptedTerms" id="acceptedTerms">
<span className={styles.checkboxLabel}>
I agree to the{" "}
<Link href="/terms">
<a className={styles.registerLink}>Terms of Service</a>
</Link>{" "}
and{" "}
<Link href="/privacy">
<a className={styles.registerLink}>
Privacy/Cookie Policy
</a>
</Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button
type="submit"
color="blue"
showSpinner={isSubmitting}
>
Sign Up
</Button>
</div>
</Form>
)}
</Formik>
</div>
</div>
</Layout>
</>
);
}
взято отсюда https://formik.org/docs/examples/async-submission
Комментарии:
1. Спасибо. Я пытаюсь понять, как использовать
isSubmitting
флаг в этом случае? Мне все еще нужноuseState
, и он все равно будет выполнять пакетные вызовы. Я думаю, я что-то упускаю?2. @Noob Nop, вы ничего не упускаете, именно так работают асинхронные функции, вы не можете ожидать, что значение будет отличаться на одну строку после асинхронного вызова. Я обновлю ответ с изменениями в коде