Skip to content

Instantly share code, notes, and snippets.

@iBasit
Last active September 13, 2018 11:43
Show Gist options
  • Save iBasit/10416c52550bd32e3f4a08b23d5b1ab5 to your computer and use it in GitHub Desktop.
Save iBasit/10416c52550bd32e3f4a08b23d5b1ab5 to your computer and use it in GitHub Desktop.
tutorial example
import React from 'react';
import { Formik, Field, Form } from 'formik';
import {bindActionCreators} from "redux";
import connect from "react-redux/es/connect/connect";
import { contactCompleted, contactHasError, contactLoading, saveContact } from "../actions/contactAction"
import * as Yup from 'yup';
/**
* TODO Contact us form
* √ - first name, last name and email request
* √ - add validation
* √ - show loading text on submit and disable button
* √ - send data to server
* √ - show thank you message or error message on failure
*/
// While you can use any validation library (or write you own), Formik
// comes with special support for Yup by @jquense. It has a builder API like
// React PropTypes / Hapi.js's Joi. You can define these inline or, you may want
// to keep them separate so you can reuse schemas (e.g. address) across your application.
const SignUpSchema = Yup.object().shape({
email: Yup.string()
.email('Invalid email address')
.required('Required'),
firstName: Yup.string()
.min(2, 'Must be longer than 2 characters')
.max(20, 'Nice try, nobody has a first name that long')
.required('Required'),
lastName: Yup.string()
.min(2, 'Must be longer than 2 characters')
.max(20, 'Nice try, nobody has a last name that long')
.required('Required'),
});
const Contact = ({saveContact, contactCompleted, contactHasError, contactLoading, isLoading, isSuccess, isError, errorMsg}) => (
<div>
<h1>Contact us</h1>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
phone: ''
}}
validationSchema={SignUpSchema}
onSubmit={values => {
contactLoading(true);
saveContact(values);
}}
render={({ errors, touched }) => (
<div>
{isSuccess ? <div className="text-success">Thank you for submitting the form</div> : ''}
{isError ? <div className="text-danger">{errorMsg}</div> : ''}
<Form className={isSuccess ? 'hidden' : ''}>
<div className="form-row col-4">
<label htmlFor="firstName">First Name</label>
<Field name="firstName" placeholder="Jane" className={errors.firstName && touched.firstName ? "form-control is-invalid" : !errors.firstName && touched.firstName ? "form-control is-valid": "form-control"} />
<div className="valid-feedback">
Looks good!
</div>
<div className="invalid-feedback">
{errors.firstName}
</div>
</div>
<br/>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" placeholder="Doe" />
{errors.lastName && touched.lastName && (
<div className="field-error text-danger">{errors.lastName}</div>
)}
<br/>
<label htmlFor="email">Email</label>
<Field name="email" placeholder="jane@acme.com" type="email" />
{errors.email && touched.email && (
<div className="field-error text-danger">{errors.email}</div>
)}
<br/>
<label>Phone</label>
<Field name="phone" placeholder="ex: 00448382922" />
<br/><br/>
<button type="submit" disabled={isLoading}>Submit</button>
{isLoading ? 'loading...' : ''}
</Form>
</div>
)}
/>
</div>
);
const mapStateToprops = (state,props) => ({
...state.contact,
...props
});
const mapDispatchToProps = dispatch => bindActionCreators({
saveContact, contactCompleted, contactHasError, contactLoading
},dispatch);
export default connect(
mapStateToprops,
mapDispatchToProps
)(Contact);
import {CONTACT_COMPLETED, CONTACT_ERROR, CONTACT_LOADING} from "../reducers/contactReducer";
export const contactCompleted = () => ({
type: CONTACT_COMPLETED,
isSuccess: true
});
export const contactLoading = (boolean) => ({
type: CONTACT_LOADING,
isLoading: boolean
});
export const contactHasError = (boolean, errorMsg) => ({
type: CONTACT_ERROR,
isError: boolean,
errorMsg
});
export const saveContact = (values) => {
return dispatch => fetch('http://httpbin.org/delay/5', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: values
})
.then((response) => {
dispatch(contactLoading(false));
dispatch(contactCompleted(true));
dispatch(contactHasError(false, ''));
console.log('response before', response);
return response.json();
})
.then((response) => {
console.log('resonse after ', response);
})
.catch((promise) => {
dispatch(contactLoading(false));
dispatch(contactHasError(true, promise.toLocaleString()));
console.log('error:', promise.toLocaleString());
});
}
export const CONTACT_LOADING = 'CONTACT_LOADING';
export const CONTACT_COMPLETED = 'CONTACT_COMPLETED';
export const CONTACT_ERROR = 'CONTACT_ERROR';
let initialState = {
isLoading: false,
isSuccess: false,
isError: false,
errorMsg: ''
};
export default function contact(state =initialState,action ){
switch (action.type){
case CONTACT_COMPLETED:
return {
...state,
isSuccess: action.isSuccess
};
case CONTACT_LOADING:
return {
...state,
isLoading: action.isLoading
};
case CONTACT_ERROR:
return {
...state,
isError: action.isError,
errorMsg: action.errorMsg
};
default:
return state;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment