How to use withFormik with yup inside reactjs class? - javascript

My purpose is to create a register form which consist of two step. For the first step, user input their credential and then I want to async validate if username is already existed against backend. If everything is alright, then he/she can click next to continue to another step but all the data is not yet submit to server at this point. The second step, user need to fill some of there information and click submit in order to complete the registration and send data to server. To achieve this, i consider create two components. The first component is responsible for user credential and another component is responsible for user detail. After these two components are created, then i will create another class which will import these two components. The third class is created to make sure that all properties is safe if user click back from second step to the first step (I am not sure if this is the right way but it is what i can think of based on my current knowledge in programming language. Please suggest me if there is a better way.).
To valid client side, I choose to use withFormik and Yup. But, the problem is that, i could not make it work and valid my client side. It always throw me lot of error by return FormikApp in render method. I have tried return App but it doesn't work too.
import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from "react-router-dom";
import {
Row,
InputGroup,
Col,
Navbar,
Nav,
NavDropdown,
Form,
FormControl,
Button
} from "react-bootstrap";
import { Form as FormikForm, Field, withFormik } from "formik";
import * as Yup from "yup";
import axios from "axios";
class UserCredential extends React.Component {
App = ({ values, errors, touched }) => (
<FormikForm className="register-form " action="">
<h3 className="register-title">Register</h3>
<Form.Group className="register-form-group">
<Field
name="username"
type="text"
placeholder="USERNAME"
className="form-control rounded register-form-control" />
{touched.username && errors.username && <p>{errors.username}</p>}
</Form.Group>
</FormikForm>
);
FormikApp = withFormik({
mapPropsToValues({ username }) {
return {
username: username || ""
};
},
validationSchema: Yup.object().shape({
username: Yup.string()
.min(6)
.max(32)
.required()
.test("username", "error message of username", async value => {
return true;
})
}),
handleSubmit(values) {
console.log(values);
}
})(App);
render() {
return (
{this.FormikApp}
)
}
}

Related

Handling custom email handlers with Firebase + NextJS

I've created the following code to have access to custom email handlers, as the firebase docs recommends.
import { useEffect } from 'react';
import { useRouter } from 'next/router'
import RecoverEmail from '../components/FirebaseHandler/RecoverEmail';
import ResetPassword from '../components/FirebaseHandler/ResetPassword';
import VerifyEmail from '../components/FirebaseHandler/VerifyEmail';
import useState from 'react-usestateref'
// http://localhost:3000/action?mode=resetPassword&oobCode=ABC123&apiKey=AIzaSy
// mode - The user management action to be completed
// oobCode - A one-time code, used to identify and verify a request
// apiKey - Your Firebase project's API key, provided for convenience
const Action = (props) => {
const router = useRouter();
const [mode, setMode, modeRef] = useState('')
const [actionCode, setActionCode, actionCodeRef] = useState('')
useEffect(() => {
console.log(router.query)
console.log('before:' + mode)
setMode(router.query.mode)
setActionCode(router.query.oobCode)
console.log('after:' + modeRef.current)
}, [router.isReady]);
switch (modeRef.current) {
case 'resetPassword':
// Display reset password handler and UI.
return <ResetPassword actionCode={actionCodeRef.current} />;
break
case 'recoverEmail':
// Display email recovery handler and UI.
return <RecoverEmail actionCode={actionCodeRef.current} />;
break
case 'verifyEmail':
// Display email verification handler and UI.
return <VerifyEmail actionCode={actionCodeRef.current} />;
break
default:
// Error: invalid mode.
return (
<div className="Action">
<h1>Error encountered</h1>
<p>The selected page mode is invalid.</p>
</div>
);
}
}
export default Action;
I've managed to success with the 'recover email' and 'verify email' cases, but I've failed achieving something with 'reset password'. I don't know what's wrong, but when I get the link and I open it, the case 'reset password' doesn't execute (it directly goes to the default one), or if it does, then I get the following 404 error from firebase, instead of being shown the ResetPassword component that allows the user to execute the functions.
As I mentioned before, I don't know exactly what could be wrong with this case since the other two are perfectly working, so any clue would be very appreciated. Thank you.

Data from API is not filled inputs fields. Formik

I create simple form on functional component ReactJS, with using Formik. Input fields my form should get data from API, when component mount. For this i'm using fetch and useEffect. After fetching, data from the API is retrieved but not filled until formik.handleChange is triggered.
If try to specify something in any input field, formik.handleChange is triggered, and all fields are immediately filled with data from the API (in my case, sould filled only email)
How i can triggered formik.handleChange when component will mount ?
import React, { useEffect } from 'react';
import { TextField, Button } from '#material-ui/core/';
import { useFormik } from 'formik';
import * as yup from "yup";
const validationSchema = yup.object({
Title: yup.string("Enter your Title").required("Title is required"),
email: yup
.string("Enter your email")
.email("Enter a valid email")
.required("Email is required"),
});
export default function Form() {
const formik = useFormik({
initialValues: {
Title: "",
email: ""
},
validationSchema: validationSchema,
onSubmit: async (values) => {
//...code of post function
//...code of post function
//...code of post function
}
});
useEffect(() => {
(async () => {
try {
let response = await fetch(
"https://run.mocky.io/v3/5be581aa-89d3-43e3-8478-7186633f8d16"
);
let content = await response.json();
formik.initialValues.email = content[0].email;
} catch (e) {
console.log(e);
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<form onSubmit={formik.handleSubmit}>
<TextField
fullWidth
id="email"
name="email"
label="Email"
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
/>
<Button color="primary" variant="contained" fullWidth type="submit">
Submit
</Button>
</form >
);
}
Link to SandBox
In addition, I have a second way with using ReactState, but I think it way are lesspreffered but it has another error: After fetching, states fill my input fields, but fail validation. When i'm trying submiting data, to validation sending default values of react State (those that came before fetch)
Link to SandBox with useState way
You were on a good path. Reassigning values to formik instance will not help. Use setFieldValue to set value after fetching data (or simply setValues if you want to set all values):
formik.setFieldValue("email", content[0].email);
or:
formik.setValues(content[0]);
Here's a modified version of your Sandbox:
https://codesandbox.io/s/jolly-sun-uppr6?file=/src/App.js
Don't forget to set your formik to enable reinitialize - https://formik.org/docs/api/formik#enablereinitialize-boolean

reactjs - putting props into the export params

I am building form components - and I want to be able to give my own unique identifiers in the exports param. I also want to learn how to push validation schemas into these export sections. I need to get more control in this section otherwise all forms are thinking they are the "'syncValidationForm'"
import React from 'react';
import { reduxForm } from 'redux-form';
import validate from './validateForm';
import warn from './warnForm';
import FieldMaker from './FieldMaker';
import ButtonMaker from './ButtonMaker';
const FormShell = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<FieldMaker fields={props.fields} />
<ButtonMaker buttons={props.buttons} pristine={pristine} submitting={submitting} reset={reset} />
</form>
)
}
export default reduxForm({
form: 'syncValidationForm', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(FormShell)
You can create a factory function and export it:
function makeForm(id) {
return reduxForm({
form: id,
validate,
warn
})(FormShell)
}
export default makeForm;
And then you can create a form with custom id:
import makeForm from './FormShell';
const FormShell = makeForm('syncValidationForm');
// ...

React: Modal containing form won't recognise a a prop of type function being passed down to it

This is a very specific issue I have searched this site and the web for hours trying to resolve it. Mod please don't disable this post with out reading completely.
I can pass function to control the state easily.
I can pass objects arrays to modal easily
This issue is specifically passing a function to a modal which contains a registration form - upon completion of the form I want to change the state.
class Users extends Component {
aPropVal = 'works fine';
// passing the following function as prop to any other (non-modal) component works fine
addUserStart = (data) => {
console.log('addUserStart has been fired')
}
render() {
return (
<div id="main">
<ModalAddUser addUserStart={this.addUserStart} aprop={this.aPropVal} />
...
</div>
)
}
}
export default Users
then the ModalAddUserObject which works perfectly in every way - exception being the function won't pass
import React, { useState } from 'react';
import { Button, FormGroup, Input, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
const ModalAddUser = (props) => {
console.log('props for ModalAddUser: ' + JSON.stringify(props))
...
}
console.log =
props for ModalAddUser: {"aprop":"works fine"}
JSON.stringify wouldn't serialize functions. if you try console.log(props) you should see your functions.

React Native: Why Does GraphQL Query With Apollo Return Undefined?

I'm currently trying to take a GraphQL query and using Apollo, display the result on my React Native app.
Here is the relevant code in App.js:
import {LoginScreen} from './src/Screens'
import ApolloClient from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
const myLink = new HttpLink({
uri: 'http://localhost:5000/graphql',
});
const client = new ApolloClient({
link: myLink,
cache: new InMemoryCache()
});
export default class App extends React.Component{
render() {
return(
<ApolloProvider client={client}>
<LoginScreen/>
</ApolloProvider>
)}
}'
And here is the relevant code in LoginScreen.js
function ShowUser({data: { loading, otsUserByUserId }}) {
if (loading) {
return <Text>Loading</Text>;
} else {
console.log("Ots user is " + otsUserByUserId)
console.log("Data: " + data)
return (
<View>
{otsUserByUserId.map(user =>
<Text>The name of user is {user.firstName} {user.lastName}.</Text>
)}
</View>
);
}
}
export default graphql(gql`
query otsUser{
otsUserByUserId(userId:1) {
firstName
lastName
}
}
`)(ShowUser)
My query works in GraphiQL as you can see:
And just to show that I'm using the correct endpoint for my link:
When running this, in my debugger, I see
This shows that data is undefined and it's a networking error. So I must be doing something wrong on my setup on the front end. In some way, I am not using Apollo correctly. It seems pretty obvious that the error is in my App.js in how I define client, but I haven't been able to get anything to work for a while now, and it's driving me nuts. I can't find any SO posts on this.
I've gone through the Apollo docs multiple times and have been trying to just get something to work for a few days now. Any help is much appreciated. Thank you for your time.
The problem is localhost only means something to your computer, but means nothing to your react native app since the server is not running on it. Try changing localhost to your computer's IP address. That should hook you up.
const myLink = new HttpLink({
uri: 'http://{COMPUTER_IP_ADDRESS_HERE}:5000/graphql',
});
Update: 11/21
Below is to deal with your additional questions left in the comments.
If you have a better idea, please do not hesitate to tell me and I will try it.
Why can't I just do console.log(props.data)?
1. How I've done it
Here's a copy/paste of a working login page from one of my demo/toy apps. I know it works. It basically does the same thing you're attempting with a couple nice additions (e.g. managed form state, passing vars to the HOC, localstorage caching). You should be able to get what you need from it and adapt it to your use case easily.
// LoginScreen.js
import React from 'react';
import { gql, graphql } from 'react-apollo';
import { Button, Input } from 'rebass';
import { AUTH_TOKEN_KEY } from '../config';
class Login extends React.Component {
state = {
form: {
email: '',
password: ''
},
submitting: false
};
handleSubmit = evt => {
evt.preventDefault();
this.setState({
submitting: true
});
const { email, password } = this.state.form;
this.props
.signinUser({ variables: { email, password } })
.then(res => {
window.localStorage.setItem(AUTH_TOKEN_KEY, res.data.signinUser.token);
window.location = '/';
})
.catch(err => console.error(err));
};
handleChange = evt => {
const { name, value } = evt.target;
this.setState({
form: {
...this.state.form,
[name]: value
}
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<h1>Login</h1>
<Input
type="text"
name="email"
label="Email"
value={this.state.form.email}
// baseRef={ref => ref.focus()}
onChange={this.handleChange}
/>
<Input
type="password"
name="password"
label="Password"
value={this.state.form.password}
onChange={this.handleChange}
/>
<Button>Login</Button>
</form>
);
}
}
const signinUser = gql`
mutation($email: String!, $password: String!) {
signinUser(email: { email: $email, password: $password }) {
token
}
}
`;
export default graphql(signinUser, { name: 'signinUser' })(Login);
2. console.log(props.data)
You should be able to log this. Not sure what you're seeing, but I'm assuming it's something like [Object] from your description. If that's true, try this console.log('props.data %j', props.data) which will convert props.data to json if possible. You can also try console.log({props}) to see the entire props tree. If neither works the way you want, then you probably have something else going on here.
If you have more questions, you should probably open new stack overflow questions. These are really meant to just be one-to-one kinds of things, one question, one answer.

Categories