Field Array example
https://www.jianshu.com/p/4b5cb1c32f40
[cc lang=”js”]
renderField 是一个组件 接收有以下props:  meta: { touched, error, submitFailed } 信息,  input, label, type 等
renderMembers 是一个 组件, 有以下props: fields ,meta: { touched, error, submitFailed } 信息,  input, label, type 等
renderMembers 里 fields 是个数组, field.push 是添加新成员
[cc lang=”js”]
const renderMembers = ({ fields, meta: { touched, error, submitFailed } }) => (
- 
      
{(touched || submitFailed) && error && {error}} 
{fields.map((member, index) => (
))}
);
const FieldArraysForm = props => {
  const { handleSubmit, pristine, reset, submitting } = props;
  return (
  );
};
const validate = values => {
  const errors = {};
  if (!values.clubName) {
    errors.clubName = ‘Required’;
  }
  if (!values.members || !values.members.length) {
    errors.members = { _error: ‘At least one member must be entered’ };
  } else {
    const membersArrayErrors = [];
    values.members.forEach((member, memberIndex) => {
      const memberErrors = {};
      if (!member || !member.firstName) {
        memberErrors.firstName = ‘Required’;
        membersArrayErrors[memberIndex] = memberErrors;
      }
      if (!member || !member.lastName) {
        memberErrors.lastName = ‘Required’;
        membersArrayErrors[memberIndex] = memberErrors;
      }
      if (member && member.hobbies && member.hobbies.length) {
        const hobbyArrayErrors = [];
        member.hobbies.forEach((hobby, hobbyIndex) => {
          if (!hobby || !hobby.length) {
            hobbyArrayErrors[hobbyIndex] = ‘Required’;
          }
        });
        if (hobbyArrayErrors.length) {
          memberErrors.hobbies = hobbyArrayErrors;
          membersArrayErrors[memberIndex] = memberErrors;
        }
        if (member.hobbies.length > 5) {
          if (!memberErrors.hobbies) {
            memberErrors.hobbies = [];
          }
          memberErrors.hobbies._error = ‘No more than five hobbies allowed’;
          membersArrayErrors[memberIndex] = memberErrors;
        }
      }
    });
    if (membersArrayErrors.length) {
      errors.members = membersArrayErrors;
    }
  }
  return errors;
};
export default validate;
[/cc]
数据对象 是[cc lang=”js”] {
	clubName:xxx
	members: [{
		firstName: xxx,
		hobbies: []
	}]
}[/cc]
material UI width Redux-form
[cc lang=”js”]
// 选择 框
const renderSelectField = (
  { input, label, meta: { touched, error }, children, …custom },
) => (
  
    children={children}
    {…custom}
  />
);
	
		
		
		
	
[/cc]
[cc lang=”js”]
//输入框
const renderTextField = (
	  { input, label, meta: { touched, error }, …custom },
	) => (
	  
	);
	
[/cc]
[cc lang=”js”]
// Radio
const renderRadioGroup = ({ input, …rest }) => (
  
  />
);
		
		
	 
[cc lang=”js”]
// 本地和服务器验证
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
export default (async function asyncValidate(values /*, dispatch */) {
  await sleep(1000); // simulate server latency
  if ([“foo@foo.com”, “bar@bar.com”].includes(values.email)) {
    return { email: “Email already Exists” };
  }
});
export default reduxForm({
  form: ‘MaterialUiForm’, // a unique identifier for this form
  validate,
  asyncValidate,
})(MaterialUiForm);[/cc]
初始化 表单数据
[cc lang=”js”]InitializeFromStateForm = reduxForm({
  form: ‘initializeFromState’, // a unique identifier for this form
})(InitializeFromStateForm);
// You have to connect() to any reducers that you wish to connect to yourself
InitializeFromStateForm = connect(
  state => ({
    initialValues: state.account.data, // pull initial values from account reducer
  }),
  { load: loadAccount }, // bind account loading action creator
)(InitializeFromStateForm);[/cc]
values lifecycle 生命周期
