Oi
Temos um painel de administração e muitos formulários no BCS, mas na comunidade React não existe um método geralmente aceito - como projetá-los para reutilização. O guia oficial do Facebook não possui informações detalhadas sobre como trabalhar com formulários em condições reais, onde a validação e a reutilização são necessárias. Alguém usa redux-form, formik, final-form, ou mesmo escreve sua própria solução.
Neste artigo, mostraremos uma das opções para trabalhar com formulários no React. Nossa pilha será assim: React + formik + Typescript. Vamos mostrar:
- O que um componente deve fazer.
- Configuração, campos e validação no nível de adereços.
- Como tornar um formulário reutilizável.
- Otimização do renderizador.
- Do que o nosso método é inconveniente.
Com a nova tarefa de negócios, aprendemos que precisaremos criar 15 a 20 formas semelhantes e, hipoteticamente, pode haver ainda mais. Tínhamos uma forma de dinossauro na configuração, que trabalhava com dados da `store`, enviava ações para salvar e executar solicitações através de` sagas`. Ela era maravilhosa, valorizando os negócios. Mas já não era expansível nem reutilizável, apenas com código ruim e adição de muletas.
A tarefa é: reescrever o formulário para que possa ser reutilizado um número ilimitado de vezes. Bem, lembre-se da programação funcional, ela possui funções puras que não usam dados externos, no nosso caso `redux`, apenas o que eles são enviados em argumentos (props).
E foi o que aconteceu.
A idéia do nosso componente é que você crie um invólucro (contêiner) e escreva nele a lógica de trabalhar com o mundo exterior (recebendo dados da loja Redux e enviando ações). Para isso, o componente do contêiner deve poder receber algumas informações através dos retornos de chamada. A lista inteira de adereços de formulário:
interface IFormProps {
Usando Formik
Usamos o componente <Formik />.
render() { const { fields, validationSchema, validateOnBlur = true, validateOnChange = true, } = this.props; return ( <Formik initialValues={fields} render={this.renderForm} onSubmit={this.handleSubmitForm} validationSchema={validationSchema} validateOnBlur={validateOnBlur} validateOnChange={validateOnChange} validate={this.validateFormLevel} /> ); }
No prop'e do formulário `validate`, chamamos o método` this.validateFormLevel`, no qual damos ao componente container a oportunidade de obter todos os campos alterados e verificar se são válidos.
private validateFormLevel = (values: FormFields) => { const { onChangeFields, validationSchema } = this.props; if (onChangeFields) { validationSchema .validate(values) .then(() => { onChangeFields(values, { isValid: true }); }) .catch(() => { onChangeFields(values, { isValid: false }); }); } }
Aqui temos que chamar a validação novamente para deixar claro para o contêiner se os campos são válidos. Ao enviar um formulário, simplesmente chamamos prop `onSubmit`:
private handleSubmitForm = (): void => { const { onSubmit } = this.props; if (onSubmit) { onSubmit(); } }
Com os adereços 1-5, tudo deve ficar claro. Vamos seguir para 'config', 'fields' e 'validationSchema'.
Adereços 'config'
interface IFieldsFormMetaModel { sectionName?: string; sectionDescription?: string; fieldsForm?: Array<{ name?: string;
Com base nessa interface, criamos uma matriz de objetos e renderizamos “section” -> “section fields” de acordo com este esquema. Assim, podemos mostrar vários campos para a seção ou em cada um de cada vez, se você precisar de um título e uma nota. Como a renderização funciona, mostraremos um pouco mais tarde.
Um pequeno exemplo de uma configuração:
export const config: IFieldsFormMetaModel[] = [ { sectionName: ' ', fieldsForm: [{ name: 'subject', label: '', type: ElementTypes.Text, }], }, { sectionName: '', sectionDescription: ' ', fieldsForm: [{ name: 'reminder', disabled: true, label: '', type: ElementTypes.CheckBox, checked: true, }], }, ];
Com base nos dados comerciais, os valores para as chaves `name` são definidos. Os mesmos valores são usados nas chaves prop `fields` para transmitir os valores originais ou alterados para o formic.
Para o exemplo acima, `fields` pode ser assim:
const fields: SomeBusinessApiFields = { subject: ' ', reminder: 'yes', }
Para validação, precisamos passar no esquema Yup. Fornecemos o formulário ao formulário com os adereços de contêiner, descrevendo as interações com dados externos, por exemplo, solicitações.
O formulário não pode influenciar o esquema de forma alguma, por exemplo:
export const CreateClientSchema: ( props: CreateClientProps, ) => Yup.MixedSchema = (props: CreateClientProps) => Yup.object( { subject: Yup.string(), description: Yup.string(), date: dateSchema, address: addressSchema(props), }, );
Otimização de renderização e campo
Para renderização, fizemos um mapa para pesquisa rápida por chave. Parece conciso e a pesquisa é mais rápida do que por `switch`.
fieldsMap: Record< ElementTypes, ( state: FormikFieldState, handlers: FormikHandlersState, field: IFieldsFormInfo, ) => JSX.Element > = { [ElementTypes.Text]: ( state: FormikFieldState, handlers: FormikHandlersState, field: IFieldsFormInfo ) => { const { values, errors, touched } = state; return ( <FormTextField key={field.name} element={field} handleChange={this.handleChangeField(handlers.setFieldValue, field.name)} handleBlur={handlers.handleBlur} value={values[field.name]} error={touched[field.name] && errors[field.name] || ''} /> ); }, [ElementTypes.TextSearch]: (...) => {...}, [ElementTypes.TextArea]: (...) => {...}, [ElementTypes.Date]: (...) => {...}, [ElementTypes.CheckBox]: (...) => {...}, [ElementTypes.RadioButton]: (...) => {...}, [ElementTypes.Select]: (...) => {...}, };
Cada campo do componente é com estado. Ele está localizado em um arquivo separado e está envolvido em `React.memo`. Todos os valores são transmitidos através de adereços, ignorando os `filhos ', para evitar renderizadores desnecessários.
Conclusão
Nosso formulário não é ideal; para cada caso, precisamos criar um invólucro de contêiner para trabalhar com dados. Salve-os na `loja`, converta e faça solicitações. Há uma repetição de código da qual você deseja se livrar. Estamos tentando encontrar uma nova solução na qual o formulário, dependendo dos objetos, terá a chave desejada da loja com campos, ações, diagramas e configurações. Em uma das postagens a seguir, contaremos o que aconteceu.