You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
1.8 KiB
JavaScript
76 lines
1.8 KiB
JavaScript
5 years ago
|
// TODO: Enable exportDefaultFrom in Babel syntax
|
||
|
import React, { useReducer } from 'react'
|
||
|
|
||
|
export const Input = require('./input.js').default
|
||
|
|
||
|
export const FormController = function FormController({children, onSubmit}){
|
||
|
const initialState = {
|
||
|
fields: {}
|
||
|
}
|
||
|
|
||
|
const reducer = (state, action)=>{
|
||
|
let fields = {...state.fields}
|
||
|
|
||
|
// Update currently changing field
|
||
|
const prevField = state.fields[action.name]
|
||
|
const updatedField = {
|
||
|
...prevField,
|
||
|
value: action.value,
|
||
|
isValid: prevField.validate?prevField.validate(action.value, fields):true
|
||
|
}
|
||
|
fields[action.name] = updatedField
|
||
|
|
||
|
// Update other fields where the validate function takes whole state
|
||
|
const fieldNames = Object.keys(fields)
|
||
|
for(const name of fieldNames){
|
||
|
if(name === action.name) continue
|
||
|
|
||
|
const field = fields[name]
|
||
|
|
||
|
if(field.validate && field.validate.length > 1)
|
||
|
fields[name] = {
|
||
|
...field,
|
||
|
isValid: field.validate(field.value, fields)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {fields}
|
||
|
}
|
||
|
|
||
|
// Update initial state
|
||
|
React.Children.forEach(children, child => {
|
||
|
if(!child.props.name) return;
|
||
|
|
||
|
initialState.fields[child.props.name] = {
|
||
|
name: child.props.name,
|
||
|
validate: child.props.validate,
|
||
|
value: child.props.initialValue,
|
||
|
isValid: true
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// Create reducer
|
||
|
const [state, dispatch] = useReducer(reducer, initialState)
|
||
|
|
||
|
const _children = React.Children.map(children, child => {
|
||
|
const {name} = child.props;
|
||
|
if(!name) return child;
|
||
|
|
||
|
const newProps = {
|
||
|
onChange: ev=>dispatch({name, value: ev.target.value}),
|
||
|
value: state.fields[name].value,
|
||
|
isValid: "" + state.fields[name].isValid
|
||
|
}
|
||
|
|
||
|
return React.cloneElement(child, newProps)
|
||
|
})
|
||
|
|
||
|
console.log(JSON.stringify(state.fields, null, 2))
|
||
|
|
||
|
return (
|
||
|
<>
|
||
|
{_children}
|
||
|
</>
|
||
|
)
|
||
|
}
|