What is the intended approach for creating reusable fields? #637
-
| Let's imagine I have a component that absolutely works only with  <SomeSpecialField name="some.special" />
// or
<Field
  name="some.special"
  children={(field) => <SomeSpecialField field={field} />}
/>However now, in order not to lose all the type checking I have to write like this and it makes the code harder to read and is code copying: <Field
  name="some.special"
  children={(field) => (
    <SomeSpecialField
      name={field.name}
      meta={field.meta}
      value={field.state.value}
      onBlur={field.handleBlur}
      onChange={field.handleChange}
    />
  )}
/>As much I understand there is no "silver bullet" at the moment so I have to choose between second variant or lose type checking. function SomeSpecialField<TName, TParentData extends DeepRecord<TName, SpecialType>>(props: {
  field: FieldApi<TParentData, TName>
}): JSX.Element {}But I failed to implement  | 
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 3 replies
-
| We'll have docs on how to do this soon. FWIW it'll be fairly complex TS types that we expect folks to copy+paste into their codebase when it's ready | 
Beta Was this translation helpful? Give feedback.
-
| Any updates on the docs? I just started to go down this path and backed off once I realized how complex the types are. :-) | 
Beta Was this translation helpful? Give feedback.
-
| Interested in this as well, so I am following here. | 
Beta Was this translation helpful? Give feedback.
-
| This is the strategy im currently using (with some opinionated behavior): adapters.tsx export type FieldProp<T> = FieldApi<any, any, any, any, T>;
/** Common input props that are handled by form library */
export type FieldInputProps = "name" | "value" | "onBlur" | "onChange" | "onFocus" | "error";
//you could just not use any adapter at all, but I wanted a degree of separation between my components and the form library.
//this is not a hook technically, but it might contain hooks in the future so for now it should be treated as one.
export function useFieldAdapter<T>(field: FieldProp<T>): InputBridgeProps<T> {
    const meta = field.state.meta;
    //just take the first error. multiple errors feel overwhelming to user.
    const error = meta.errors.find(err => typeof err === "string");
    return {
        name: field.name,
        value: field.state.value,
        meta: {
            error: error,
            touched: meta.isTouched,
            dirty: meta.isDirty,
            validating: meta.isValidating,
            submitting: field.form.state.isSubmitting, //is this the right way to get form metadata?
        },
        events: {
            onChange: (val) => field.handleChange(val),
            onBlur: () => field.handleBlur(),
            onFocus: () => undefined, //tanstack does not use onFocus, but other libraries do.
        }
    };
}checkbox-field.tsx (have to create a wrapper for each input type but this is good practice anyways...) import { FieldInputProps, FieldProp, useFieldAdapter } from "../adapters";
import { CheckboxInput, CheckboxInputProps } from "components/inputs/checkbox-input";
export type CheckboxFieldProps = (
    & Omit<CheckboxInputProps, FieldInputProps>
    & {
        field: FieldProp<boolean>,
    }
);
export default function CheckboxField(props: CheckboxFieldProps) {
    const { field, ...passthrough } = props;
    const { name, value, events, meta } = useFieldAdapter(field);
    //this input is another non form connected wrapper
    return <CheckboxInput
        {...passthrough}
        name={name}
        value={value}
        {...events}
        error={meta.error}
        disabled={meta.submitting || props.disabled}
        required={props.required}
    />;
}then you can use it like this <Field
    name="requireCertificate"
    children={field => (
        <CheckboxField
            label="Require Certificate"
            field={field}
        />
    )}
/> | 
Beta Was this translation helpful? Give feedback.
We'll have docs on how to do this soon.
FWIW it'll be fairly complex TS types that we expect folks to copy+paste into their codebase when it's ready