How are existing reactive observables connected to Alpine.js?
The Dexie.js website lists a few examples with React and Svelte but how would I use Dexie.js liveQuery with Alpine.js? Is it as simple as passing the variable to x-data?
You cannot pass directly a liveQuery object to an Alpine.js property because it will lose reactivity. We need to create a small wrapper that updates Alpine.js data when a liveQuery returns new data. Here I provide a small example that uses a products table, the Alpine.js component just lists the products and there's a small form that can add new products to the DB.
Example database definition in db.js:
import Dexie from 'dexie'
export const db = new Dexie('myDatabase')
db.version(1).stores({
products: '++id, name, color',
})
In main.js we make db and liveQuery global:
import Alpine from 'alpinejs'
import { liveQuery } from "dexie"
window.liveQuery = liveQuery
import { db } from './db'
window.db = db
window.Alpine = Alpine
window.Alpine.start()
The example Alpine.js component:
<div x-data="productsComponent">
<div>
<input type="text" x-model="name" placeholder="Name" />
<input type="text" x-model="color" placeholder="Color" />
<button #click="add">Add product</button>
</div>
<div>
<h2>Products</h2>
<template x-for="p in products">
<div x-text="`ID: ${p.id} Name: ${p.name} Color: ${p.color}`"></div>
</template>
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('productsComponent', () => ({
products: [],
name: '',
color: '',
observe(dataName, observable) {
const subscription = observable.subscribe({
next: val => {this[dataName] = val}
})
},
init() {
this.observe('products', liveQuery(() => db.products.toArray()))
},
async add() {
const id = await db.products.add({
name: this.name,
color: this.color,
})
this.name = ''
this.color = ''
}
}))
})
</script>
In the observe method we subscribe the specific liveQuery event and update the Alpine.js data when it changes.
import { Formik, Form, Field } from "formik";
import { Button } from "antd";
const AddUser = () => {
const initialValues = {
name: "",
};
return (
<>
<Formik
initialValues={initialValues}
onSubmit=(values) => {
alert("hi");//calling mamy times
Here added api call (post method)
}}
>
{({ isValid, submitForm, isSubmitting, values }) => {
return (
<Form>
<Field
name="name"
label="Name"
placeholder="Dataset Name"
/>
<Button
type="primar"
htmltype="submit"
loading=(props.addingdata) // this is my reducer state intial was false after post call request became true and success state value false
>
Add Dataset
</Button>
</Form>
);
}}
</Formik>
</div>
</>
);
};
export default AddUser;
I have simple formik form antd button I have used when click submit button post api calling twice and thrice even If I added loading property in button why its happening like this?
I'm trying to use a react modal to allow someone to change a value and have the modal buttons be dynamic such that initially there are Cancel / Submit buttons, but after Submit is pressed and the value is changed, the buttons are replaced with a Close button.
The problem I am having is that using "{modalButtonGroup}" in the modal results in "tmpName" being undefined when "handleSetNameSubmit" is called. If I instead comment out the "{modalButtonGroup}" line and just use hard coded buttons (which are currently commented out in the below code), then "tmpName" is set correctly when "handleSetNameSubmit" is called.
Is there some aspect of state context that causes "tmpName" to not be known when "{modalButtonGroup}" is used?
import { useState, useEffect } from 'react';
import { Row, Table, Form, Button, Modal, Alert } from 'react-bootstrap';
const System = () => {
const [tmpName, setTmpName] = useState();
const [showName, setShowName] = useState(false);
const handleClose = () => {
setShowName(false);
}
const handleCancel = () => {
setShowName(false);
};
const handleSetNameSubmit = () => {
console.log('tmpName: ', tmpName);
//code to change the name to tmpName
setModalButtonGroup(modalButtonsPostSubmit);
}
const modalButtonsPreSubmit = () => {
return (
<>
<Button variant="secondary" onClick={handleCancel}>
Cancel
</Button>
<Button variant="primary" onClick={handleSetNameSubmit}>
Submit
</Button>
</>
)
};
const modalButtonsPostSubmit = () => {
return (
<>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</>
)
};
const [modalButtonGroup, setModalButtonGroup] = useState(modalButtonsPreSubmit);
return (
<>
<div className="card">
<h5>System</h5>
<Table variant="dark" responsive>
<tr>
<td>Name:</td>
<td>Name <Button onClick={() => setShowName(true)}>Edit</Button></td>
</tr>
</Table>
</div>
{/* Set Name */}
<Modal show={showName} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Set Name</Modal.Title>
</Modal.Header>
<Modal.Body>
<span>
<Form.Control
type="text"
defaultValue=name
onChange={(event) => setTmpName(event.target.value)}
/>
</span>
</Modal.Body>
<Modal.Footer>
{modalButtonGroup}
{/*<Button variant="secondary" onClick={handleCancel}>*/}
{/* Cancel*/}
{/*</Button>*/}
{/*<Button variant="primary" onClick={handleSetNameSubmit}>*/}
{/* Submit*/}
{/*</Button>*/}
</Modal.Footer>
</Modal>
}
export default System;
UPDATE, I tried updating the code per suggestion as follows but now no buttons are appearing at all.
import { useState, useEffect } from 'react';
import { Row, Table, Form, Button, Modal, Alert } from 'react-bootstrap';
const System = () => {
const [tmpName, setTmpName] = useState();
const [showName, setShowName] = useState(false);
const [submitted, setSubmitted] = useState(false);
const handleClose = () => {
setShowName(false);
}
const handleCancel = () => {
setShowName(false);
};
const handleSetNameSubmit = () => {
console.log('tmpName: ', tmpName);
//code to change the name to tmpName
setSubmitted(modalButtonsPostSubmit);
}
const modalButtonsPreSubmit = () => {
return (
<>
<Button variant="secondary" onClick={handleCancel}>
Cancel
</Button>
<Button variant="primary" onClick={handleSetNameSubmit}>
Submit
</Button>
</>
)
};
const modalButtonsPostSubmit = () => {
return (
<>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</>
)
};
const buttons = submitted ? modalButtonsPostSubmit : modalButtonsPreSubmit;
return (
<>
<div className="card">
<h5>System</h5>
<Table variant="dark" responsive>
<tr>
<td>Name:</td>
<td>Name <Button onClick={() => setShowName(true)}>Edit</Button></td>
</tr>
</Table>
</div>
{/* Set Name */}
<Modal show={showName} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Set Name</Modal.Title>
</Modal.Header>
<Modal.Body>
<span>
<Form.Control
type="text"
defaultValue=name
onChange={(event) => setTmpName(event.target.value)}
/>
</span>
</Modal.Body>
<Modal.Footer>
{buttons}
{/*<Button variant="secondary" onClick={handleCancel}>*/}
{/* Cancel*/}
{/*</Button>*/}
{/*<Button variant="primary" onClick={handleSetNameSubmit}>*/}
{/* Submit*/}
{/*</Button>*/}
</Modal.Footer>
</Modal>
}
export default System;
Here's what's happening. It's kind of complicated because of the unusual way in which you have written your component. I'll suggest a simpler way to do it below, but it might be educational to unpack what's going on.
Your <System> component renders for the first time:
tmpName is undefined
the handleNameSubmit function is generated and it "closes over" the current value of tmpName. This means every time this particular function value is called, it will always console.log 'tmpName: undefined'. See background on JavaScript closures
the modalButtonsPreSubmit function is generated and it closes over the current value of handleNameSubmit and binds this value to the submit button click event.
Then, you pass the modalButtonsPreSubmit function as the initial value of a useState hook. The way that useState works, this initial value is only used in the first render (see docs). The modalButtonsGroup value returned by this useState call will be frozen to this particular value (with all the closures) through subsequent re-renders, until you change it by calling setModalButtonsPreSubmit with a new function.
The user types some text in the textbox. For each character your onChange handler calls setTempName, which triggers the <System> component to re-render with a new value in the tmpName state. However, modalButtonsPreSubmit is still frozen to what it was in the first render.
The user clicks "Submit", which triggers the version handleNameSubmit that was generated on the first render, when tmpName was undefined.
The way to simplify things so that it works as expected is to not store functions in state. That way they'll get re-generated on each re-render with fresh values for any other state that they reference.
So instead of..
const modalButtonsPreSubmit = () => (
<> {/* Markdown for "Submit" and "Cancel" buttons */} </>
);
const modalButtonsPostSubmit = () => (
<> {/* Markdown for "Close" button */} </>
);
const [modalButtonGroup, setModalButtonGroup] = useState(modalButtonsPreSubmit);
return (
<div>
{/* The rest of the app */}
{modalButtonGroup}
</div>
);
You'd do something like this...
const [submitted, setSubmitted] = useState(false);
const buttons = submitted ?
<> {/* Markdown for "Close" button */} </> :
<> {/* Markdown for "Submit" and "Cancel" buttons */} </>;
return (
<div>
{/* The rest of the app */}
{buttons}
</div>
);
See this codesandbox for a working solution.
I have a yup validation with API response requirement for a react hook form.
My form is like:
import React from "react";
import useForm from "react-hook-form";
import { schema } from "./schema";
import { useTestProps } from "./useTestProps";
function Sub({ title, showForm }) {
const { register, handleSubmit, errors } = useForm({
validationSchema: schema
});
const { data } = useTestProps();
const onSubmit = (data) => {
//submit form
};
// console.log(errors);
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<label>{title}</label>
<input type="text" name="iip" ref={register} />
<br />
{errors.iip && <p>{errors.iip.message}</p>}
<br />
<label>Email</label>
<input type="text" name="email" ref={register} />
<br />
{errors.email && <p>{errors.email.message}</p>}
<br />
<input type="submit" />
</form>
</div>
);
}
export default Sub;
Validation schema of the form is like this,
//schema.js
import * as yup from "yup";
export const schema = yup.object().shape({
iip: yup
.string()
.required()
.test("validate with testProps", "iip not found", (value) => {
// validate that value should be one of testProps
// if value is in data, return true, or return false
return true
}),
email: yup.string().email().required()
});
My requirement is to validate iip field with data returned from API call in useTestProps which is like this,
{
"data": ["test1", "test2", "test3"]
}
How can I access data in schema object test where I can compare user entered value with JSON response?
Homepage.js
import React, { Component } from 'react';
import { Route, Redirect, withRouter } from 'react-router-dom';
import $ from 'jquery';
import { css } from 'glamor';
import { ToastContainer } from 'react-toastify';
import toast from '../toast';
import { BarLoader } from 'react-spinners';
// ---------------- Custom components
import Header from '../Header/Header';
import Footer from '../Footer/Footer';
import RelayAnimation from '../RelayAnimation/RelayAnimation';
import UserLoginForm from '../UserLoginForm/UserLoginForm';
import UserSignUpForm from '../UserSignUpForm/UserSignUpForm';
import PassResetReqForm from '../PassResetReqForm/PassResetReqForm';
import PassResetForm from '../PassResetForm/PassResetForm';
import './HomePage.css';
// --------- Message for Network Error
const Msg = () => (
<div>
Error please, try again later <br /> or reload the Page.
</div>
);
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
this.toggleLoader = this.toggleLoader.bind(this);
this.notifySuccess = this.notifySuccess.bind(this);
this.notifyError = this.notifyError.bind(this);
}
notifySuccess(msg) {
toast.success(msg);
}
notifyError(msg) {
toast.error(msg);
}
// --------- Toast Notifications ---------------
// notify = (status) => {
// // --------- Server Issue Toaster
// if (status === 'Bad Gateway') {
// toast.error(<Msg />, {
// className: {
// color: '#fff',
// minHeight: '60px',
// borderRadius: '8px',
// boxShadow: '2px 2px 20px 2px rgba(0,0,0,0.3)'
// }
// });
// }
// }
toggleLoader() {
this.setState({
loading: !this.state.loading
});
}
isAuthenticated() {
const token = localStorage.getItem('authToken');
if (token) {
return true;
}
}
componentDidMount() {
const currentLocationPath = this.props.location.pathname;
const urlForEmailVerification = currentLocationPath.includes('/api/v1/verifyEmailUser/');
if (urlForEmailVerification) {
const { token } = this.props.match.params; // token value from url params passed by <Route/>
if (token) {
const url = `/api/v1/verifyEmailUser/${token}`;
// api call to make the user's account verified in db based on token in url
$.ajax({
url: url,
dataType: 'json',
type: 'GET',
success: function (res) {
console.log(res);
this.notifySuccess('emailVerified');
this.props.history.push('/');
}.bind(this),
error: function (xhr, status, err) {
console.error(url, status, err.toString());
}.bind(this)
});
}
}
}
render() {
const currentLocationPath = this.props.location.pathname;
const isAuthenticated = this.isAuthenticated();
const resetPasswordPathname = currentLocationPath.includes('/api/v1/resetPassword/');
if (!isAuthenticated) {
return (
<div className="App d-flex flex-column">
{/* Navbar with brand logo and language change dropdown and signup/login button */}
< Header />
{/* Main Section with RelayStream Animation graphic and forms */}
<div className="container py-4 py-md-0 pt-lg-4 d-flex flex-grow" >
<div className={'LoginScreen d-flex align-items-center align-items-lg-start ' +
((currentLocationPath === '/login' ||
currentLocationPath === '/signup' ||
currentLocationPath === '/forgot-password' ||
resetPasswordPathname) ? 'justify-content-around' : 'justify-content-center')}>
{/* RelayStream Animation graphic */}
<RelayAnimation />
{/* forms to switch between based on path change by <Router/> */}
<Route path="/login" component={(props) => <UserLoginForm {...props} notifySuccess={this.notifySuccess} notifyError={this.notifyError} toggleLoader={this.toggleLoader} />} />
<Route path="/signup" component={(props) => <UserSignUpForm {...props} notifySuccess={this.notifySuccess} notifyError={this.notifyError} toggleLoader={this.toggleLoader} />} />
<Route path="/forgot-password" component={(props) => <PassResetReqForm {...props} notifySuccess={this.notifySuccess} notifyError={this.notifyError} toggleLoader={this.toggleLoader} />} />
<Route path="/api/v1/resetPassword/:token" component={(props) => <PassResetForm {...props} notifySuccess={this.notifySuccess} notifyError={this.notifyError} toggleLoader={this.toggleLoader} />} />
</div>
</div >
{/* Footer with copyright message */}
<Footer />
<div className={this.state.loading ? 'loader flex-column' : 'd-none'}>
<span className="loader__title">Loading...</span>
<BarLoader color={'#36D7B7'} loading={this.state.loading} />
</div>
{/* React toastify for toast notification */}
<ToastContainer className={{ textAlign: 'center' }} progressClassName={css({ background: '#007aff' })} />
</div >
);
} else {
return <Redirect to={'/dashboard'} />;
}
}
}
export default withRouter(HomePage);
UserLoginForm.js
import React, { Component } from 'react';
import { Link, Redirect } from 'react-router-dom';
import $ from 'jquery';
import { Animated } from 'react-animated-css';
import SocialButton from '../SocialButton/SocialButton';
// ---------------- Form components
import Form from 'react-validation/build/form';
import Button from 'react-validation/build/button';
// ---------------- Custom Form components & validations
import { Email, Password, required, noSpace, minChar8, email } from '../formValidation';
import FontAwesomeIcon from '#fortawesome/react-fontawesome';
import facebook from '#fortawesome/fontawesome-free-brands/faFacebookF';
import google from '#fortawesome/fontawesome-free-brands/faGooglePlusG';
import './UserLoginForm.css';
class UserLoginForm extends Component {
constructor(props) {
super(props);
this.state = {
fireRedirect: false
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSocialLogin = (user) => {
const provider = user._provider;
const name = user._profile.name;
const email = user._profile.email;
const profilePic = user._profile.profilePicURL;
const token = user._token.accessToken;
const data = { provider, name, email, profilePic, token };
console.log(data);
const url = '/api/v1/loginWithFacekbook'; // social login's api url
// api call for social logins
$.ajax({
url: url,
dataType: 'json',
type: 'POST',
data: data,
success: function (res) {
console.log('success response after api call ===>>', res);
const generatingAuthToken = res.object.generatingAuthToken;
const apikey = generatingAuthToken.apiKey;
const authToken = generatingAuthToken.authToken;
localStorage.setItem('apiKey', apikey);
localStorage.setItem('authToken', authToken);
// if social login was successful then redirect user to dashboard
this.setState({ fireRedirect: true });
}.bind(this),
error: function (xhr, status, err) {
console.log(status);
// if there was network issue notify user to try again later or refresh page
this.props.notifyError(err.toString());
console.error(url, status, err.toString());
}.bind(this)
});
}
handleSocialLoginFailure = (err) => {
console.error(err)
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
// input field animation code - adds class to current focused input field's parent
if (value) {
target.parentElement.classList.add('input--filled');
} else {
target.parentElement.classList.remove('input--filled');
}
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
// show loading spinner
this.props.toggleLoader();
// get data from all field in form
const data = this.form.getValues();
const url = '/api/v1/loginUser'; // user login api url
// api call to generate token and apikey and login user to dashboard
$.ajax({
url: url,
dataType: 'json',
type: 'POST',
data: data,
success: function (res) {
console.log('success response after api call ===>>', res);
const obj = res.object;
const loginStatus = res.status;
const msg = res.message;
// check if authToken and apiKey was received
if (obj) {
// if data is found in database check if credentials provided were correct
if (loginStatus) {
JSON.stringify(obj);
// save apiKey and token in loacalStorage
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
let val = obj[key];
localStorage.setItem(key, val);
}
}
// turn off loader spinner
this.props.toggleLoader();
this.setState({ fireRedirect: true });
// if credentials were correct accept login then redirect user to dashboard
} else { // if credentials were wrong
// turn off loader spinner
// this.props.toggleLoader();
// then notify about wrong credentials
this.props.notifyError(msg);
}
} else { // if data was not found in database notify user to signup first
this.props.notifyError(msg);
// turn off loader spinner
// this.props.toggleLoader();
}
}.bind(this),
error: function (xhr, status, err) {
console.log(status);
// if there was network issue notify user to try again later or refresh page
this.props.notify(err.toString());
console.error(url, status, err.toString());
}.bind(this)
});
}
render() {
const { fireRedirect } = this.state;
return (
<Animated className="form-animation" animationIn="fadeInRight" animationOut="fadeOutLeft" isVisible={true}>
<Form className="userLoginForm" ref={c => { this.form = c }} onSubmit={this.handleSubmit} noValidate>
<h2 className="formTitle text-center">LOG IN</h2>
<Email
required
pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$"
id="email"
name="email"
type="email"
className="input__field input__field--madoka"
onChange={this.handleInputChange}
validations={[required, email]} />
{/* must wrap Password Field Component with "div.form-group" */}
<div className="form-group">
<Password
required
id="password"
name="password"
type="password"
minLength="8"
className="input__field input__field--madoka"
onChange={this.handleInputChange}
validations={[noSpace, required, minChar8]} />
{/* Optional Link Component below...
Note: If there is no requirement of Link or any Other Element just below <Password/> input field
in entire project then the wrapping "div.form-group" can also be put inside
Password Component's Template Located in formValidation.js file*/}
<Link to="/forgot-password" className="float-right forgotPassword">
<small>Forgot password ?</small>
</Link>
</div>
<div className="form-group submitGroup text-center">
<Button type="submit" className="btn btn--submit btn-rounded btn-outline-primary mx-auto">LOG IN</Button>
</div>
{/* login buttons for facebook and google login */}
<div className="socialLogin mx-auto">
{/* <a href="#" className="socialBtn socialBtn--facebook rounded-circle">
<FontAwesomeIcon icon={facebook} />
</a> */}
<SocialButton
className="socialBtn socialBtn--facebook rounded-circle"
provider='facebook' appId='873380466175223'
onLoginSuccess={this.handleSocialLogin}
onLoginFailure={this.handleSocialLoginFailure}
redirect="/dashboard">
<FontAwesomeIcon icon={facebook} />
</SocialButton>
<span className="seperator" />
<SocialButton
className="socialBtn socialBtn--googlePlus rounded-circle"
provider="google"
appId="843586925977-d7j31p5j0me5kqvcp29nr9s37reg5b5u.apps.googleusercontent.com"
onLoginSuccess={this.handleSocialLogin}
onLoginFailure={this.handleSocialLoginFailure}>
<FontAwesomeIcon icon={google} />
</SocialButton>
{/* <a href="#" className="socialBtn socialBtn--googlePlus rounded-circle">
<FontAwesomeIcon icon={google} />
</a> */}
</div>
{/* code to redirect user to dashboard page after successful login */}
{fireRedirect && (<Redirect to={'/dashboard'} />)}
</Form>
</Animated>
);
}
}
export default UserLoginForm;
UserSignUpForm.js
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import $ from 'jquery';
import { Animated } from 'react-animated-css';
// ---------------- Form components
import Form from 'react-validation/build/form';
import Button from 'react-validation/build/button';
// ---------------- Custom Form components & validations
import { UserName, Email, NewPassword, ConfirmPassword, noSpace, required, minChar8, email, confirmPassword } from '../formValidation';
import './UserSignUp.css';
class UserSignUpForm extends Component {
constructor(props) {
super(props);
this.state = {
userName: '',
email: '',
password: '',
confirmPassword: '',
fireRedirect: false
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
// input field animation code - adds class to current focused input field's parent
if (value) {
target.parentElement.classList.add('input--filled');
} else {
target.parentElement.classList.remove('input--filled');
}
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
const data = this.form.getValues();
console.log(data);
// api call to sign up user
$.ajax({
url: '/api/v1/user',
dataType: 'json',
type: 'POST',
data: data,
success: function (res) {
console.log('success response after api call ===>>', res);
const signUpStatus = res.status;
const msg = res.message;
if (signUpStatus) {
// if signup was successful notify user
this.props.notifySuccess(msg);
// redirect user to login form
this.setState({ fireRedirect: true });
} else {
this.props.notifyError(msg); // notify user on signup fail
}
}.bind(this),
error: function (xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
}
render() {
const { fireRedirect } = this.state;
return (
<Animated className="form-animation" animationIn="fadeInRight" animationOut="fadeOutLeft" isVisible={true}>
<Form className="userSignUpForm" ref={c => { this.form = c }} onSubmit={this.handleSubmit}>
<h2 className="formTitle text-center">SIGN UP</h2>
<UserName
required
id="userName"
name="userName"
ref={c => { this.UserName = c }}
value={this.state.userName}
type="text"
className="input__field input__field--madoka"
validations={[required]}
onChange={this.handleInputChange} />
<Email
required
pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$"
id="email"
name="email"
ref={c => { this.Email = c }}
value={this.state.email}
type="email"
className="input__field input__field--madoka"
validations={[required, email]}
onChange={this.handleInputChange} />
<div className="form-group">
<NewPassword
required
id="password"
name="password"
ref={c => { this.NewPassword = c }}
value={this.state.password}
type="password"
minLength="8"
className="input__field input__field--madoka"
onChange={this.handleInputChange}
validations={[noSpace, required, minChar8]} />
</div>
<div className="form-group">
<ConfirmPassword
required
id="confirmPassword"
name="confirmPassword"
ref={c => { this.ConfirmPassword = c }}
value={this.state.confirmPassword}
type="password"
minLength="8"
className="input__field input__field--madoka"
onChange={this.handleInputChange}
validations={[noSpace, required, confirmPassword]} />
</div>
<div className="form-group submitGroup text-center">
<Button type="submit" className="btn btn--submit btn-rounded btn-outline-primary mx-auto">SIGN UP</Button>
</div>
{/* code to redirect user to dashboard page after successful login */}
{fireRedirect && (<Redirect to={'/login'} />)}
</Form>
</Animated>
);
}
}
export default UserSignUpForm;
i am facing many issues. first i have a spinner in homepage.js which shows as overlay on whole page when this.state.loading = true, initially it is set to False in constructor.
Issues 1.) when we submit the login form (if signup was done already ) the loader shows for fraction of second on screen but " this.setState({ fireRedirect: true }); " this code is supposed to redirect user to dashboard which it does but gives error in console :
index.js:2178 Warning: Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
index.js:2178 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the UserLoginForm component.
Issue 2.) If i create a new user from UserSignUpForm which redirects us to UserLoginForm. now if i try to login i get only this error:
index.js:2178 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the UserLoginForm component.
Issue 3.) If i remove or comment "this.toggleLoader();" from the ajax's success functions right before " this.setState({ fireRedirect: true }); " this line. then the loader shows on screen but doesn't go away even page doesn't redirect and console gives this error:
index.js:2178 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the UserLoginForm component.