@36node/redux-form
Version:
A higher order component decorator form using Redux and React
158 lines (124 loc) • 3.02 kB
JavaScript
import { isForm, Types } from "./action";
import { setWith, clone, get } from "lodash";
import { Forms } from "./forms";
/**
* field init state
*/
export const initFieldState = {
name: undefined, //field name
dirty: false, // is dirty
touched: false, // is touched
value: undefined, // field value
validating: undefined, // is validating
errors: undefined, // validate errors
};
export const initState = {
fields: {},
meta: {},
};
function registerField(fields = {}, name, initialValue) {
const originalField = get(fields, name);
// if name had registered, register action lose efficacy
if (originalField) {
return fields;
}
const filedState = { ...initFieldState, name, value: initialValue };
return {
...fields,
[name]: filedState,
};
}
function changeField(fields = {}, field = {}) {
const { name, ...rest } = field;
const newField = { ...(fields[name] || initFieldState), name, ...rest };
return {
...fields,
[name]: newField,
};
}
function r(state = initState, action) {
const { payload = {}, meta = {}, type } = action;
if (type === Types.registerField) {
// need field name
const { name, initialValue } = payload;
if (!name) {
return state;
}
const newFileds = registerField(state.fields, name, initialValue);
return {
...state,
fields: newFileds,
meta,
};
}
if (type === Types.registerMutilFields) {
const { fields = [] } = payload;
const newFields = fields.reduce((acc, cur) => {
const { name, initialValue } = cur;
if (!name) {
return acc;
}
return registerField(acc, name, initialValue);
}, state.fields);
return {
...state,
fields: newFields,
meta,
};
}
if (type === Types.changeField) {
const { name } = payload;
if (!name) {
return state;
}
const newFields = changeField(state.fields, payload);
return {
...state,
fields: newFields,
meta,
};
}
if (type === Types.changeMutilFields) {
const { fields = [] } = payload;
const newFields = fields.reduce((acc, cur) => {
const { name } = cur;
if (!name) {
return acc;
}
return changeField(acc, cur);
}, state.fields);
return {
...state,
fields: newFields,
meta,
};
}
if (type === Types.reset) {
const { initialValues = {} } = payload;
const newFileds = {};
for (const name in state.fields) {
newFileds[name] = { ...initFieldState, value: initialValues[name] };
}
return {
...state,
fields: newFileds,
meta,
};
}
return state;
}
export default function reducer(state = {}, action) {
if (!isForm(action)) return state;
const { key } = action;
if (!key) return state;
const form = Forms.get(key);
if (!form) {
return state;
}
return setWith(
{ ...state },
form.reduxPath,
r(get(state, form.reduxPath), action),
clone
);
}