Skip to content

Commit

Permalink
bug fix setStateSchema not enabling button if there's no error
Browse files Browse the repository at this point in the history
  • Loading branch information
llauderesv committed Apr 18, 2020
1 parent 15c288f commit 7c1e6a8
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import Form from './Form';
import Form from './example/Form';

import logo from './logo.svg';
import './App.css';
Expand Down
File renamed without changes.
12 changes: 6 additions & 6 deletions src/Form/index.js → src/example/Form/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import useForm from '../useForm';
import useForm from '../../lib';
import './index.css';

function Form() {
Expand All @@ -10,7 +10,7 @@ function Form() {
tags: { value: '', error: '' },
};

const delay = () => new Promise(resolve => setTimeout(resolve, 3000));
const delay = () => new Promise((resolve) => setTimeout(resolve, 3000));

// Create your own validationStateSchema
// stateSchema property should be the same in validationStateSchema
Expand All @@ -19,21 +19,21 @@ function Form() {
first_name: {
required: true,
validator: {
func: value => /^[a-zA-Z]+$/.test(value),
func: (value) => /^[a-zA-Z]+$/.test(value),
error: 'Invalid first name format.',
},
},
last_name: {
required: true,
validator: {
func: value => /^[a-zA-Z]+$/.test(value),
func: (value) => /^[a-zA-Z]+$/.test(value),
error: 'Invalid last name format.',
},
},
tags: {
required: true,
// required: true,
validator: {
func: value => /^(,?\w{3,})+$/.test(value),
func: (value) => /^(,?\w{3,})+$/.test(value),
error: 'Invalid tag format.',
},
},
Expand Down
67 changes: 37 additions & 30 deletions src/useForm.js → src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,24 @@ function useForm(
// Get a local copy of stateSchema
useEffect(() => {
setStateSchema(stateSchema);
setDisable(true); // Disable button in initial render.

setInitialErrorState();
}, []); // eslint-disable-line

// Set a brand new field values and errors
// Set a brand new field values and errors
// If stateSchema changes
useEffect(() => {
const values = get_prop_values(state, VALUE);
const errors = Object.keys(values).reduce((accu, curr) => {
accu[curr] = validateField(curr, values[curr]);
return accu;
}, {});

// Marked form as dirty if state was changed.
setIsDirty(true);

setValues(values);
setErrors(
Object.keys(values).reduce((accu, curr) => {
accu[curr] = validateField(curr, values[curr]);
return accu;
}, {})
);
setErrors(errors);
}, [state]); // eslint-disable-line

// For every changed in our state this will be fired
Expand All @@ -50,35 +53,41 @@ function useForm(
}
}, [errors, isDirty]); // eslint-disable-line

// Set a value of a specific field
// Set field value to specific field.
const setFieldValue = ({ name, value }) => {
setValues(prevState => ({ ...prevState, [name]: value }));
setDirty(prevState => ({ ...prevState, [name]: true }));
setValues((prevState) => ({ ...prevState, [name]: value }));
setDirty((prevState) => ({ ...prevState, [name]: true }));
};

// Set an error of a specific field
const setFieldError = ({ name, error }) =>
setErrors(prevState => ({ ...prevState, [name]: error }));
// Set to specific field.
const setFieldError = ({ name, error }) => {
setErrors((prevState) => ({ ...prevState, [name]: error }));
};

// Validate fields in forms
// Function used to validate form fields
const validateField = useCallback(
(name, value) => {
const validator = stateValidatorSchema;
const fieldValidator = stateValidatorSchema[name];
// Making sure that stateValidatorSchema name is same in
// stateSchema
if (!validator[name]) return;

const field = validator[name];
if (!fieldValidator) {
return;
}

let error = '';
error = is_required(value, field.required);
error = is_required(value, fieldValidator['required']);

if (is_object(field['validator']) && error === '') {
const validateFieldByCallback = field['validator'];
// Bail out if field is not required and no value set.
// To prevent proceeding to validator function
if (!fieldValidator['required'] && !value) {
return error;
}

// Run custom validator function
if (error === '' && is_object(fieldValidator['validator'])) {
// Test the function callback if the value is meet the criteria
if (!validateFieldByCallback['func'](value, values)) {
error = validateFieldByCallback['error'];
if (!fieldValidator['validator']['func'](value, values)) {
error = fieldValidator['validator']['error'];
}
}

Expand All @@ -90,7 +99,7 @@ function useForm(
// Set Initial Error State
// When hooks was first rendered...
const setInitialErrorState = useCallback(() => {
Object.keys(errors).map(name =>
Object.keys(errors).map((name) =>
setFieldError({ name, error: validateField(name, values[name]) })
);
}, [errors, values, validateField]);
Expand All @@ -100,14 +109,14 @@ function useForm(
// Wrapped in useCallback to cached the function to avoid intensive memory leaked
// in every re-render in component
const validateErrorState = useCallback(
() => Object.values(errors).some(error => error),
() => Object.values(errors).some((error) => error),
[errors]
);

// Use this callback function to safely submit the form
// without any errors in state...
const handleOnSubmit = useCallback(
event => {
(event) => {
event.preventDefault();

// Making sure that there's no error in the state
Expand All @@ -121,9 +130,7 @@ function useForm(

// Event handler for handling changes in input.
const handleOnChange = useCallback(
event => {
setIsDirty(true);

(event) => {
const name = event.target.name;
const value = event.target.value;

Expand Down
File renamed without changes.

0 comments on commit 7c1e6a8

Please sign in to comment.