feat: remove getFormProps to support React Native

This commit is contained in:
Corbin Crutchley
2023-09-03 01:00:45 -07:00
committed by Corbin Crutchley
parent 0d7e545c1d
commit 2a31bd8219
7 changed files with 38 additions and 64 deletions

View File

@@ -7,10 +7,6 @@ title: Form API
When using `@tanstack/react-form`, the [core form API](../../reference/formApi) is extended with additional methods for React-specific functionality:
- ```tsx
getFormProps: () => FormProps
```
- A function that returns props for the form element.
- ```tsx
Field: FieldComponent<TFormData>
```

View File

@@ -26,20 +26,20 @@ In the example below, you can see TanStack Form in action with the React framewo
[Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-form/tree/main/examples/react/simple)
```tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { useForm } from "@tanstack/react-form";
import type { FieldApi } from "@tanstack/react-form";
import React from 'react'
import ReactDOM from 'react-dom/client'
import { useForm } from '@tanstack/react-form'
import type { FieldApi } from '@tanstack/react-form'
function FieldInfo({ field }: { field: FieldApi<any, any> }) {
return (
<>
{field.state.meta.touchedError ? (
<em>{field.state.meta.touchedError}</em>
) : null}{" "}
{field.state.meta.isValidating ? "Validating..." : null}
) : null}{' '}
{field.state.meta.isValidating ? 'Validating...' : null}
</>
);
)
}
export default function App() {
@@ -47,40 +47,46 @@ export default function App() {
// Memoize your default values to prevent re-renders
defaultValues: React.useMemo(
() => ({
firstName: "",
lastName: "",
firstName: '',
lastName: '',
}),
[],
),
onSubmit: async (values) => {
// Do something with form data
console.log(values);
console.log(values)
},
});
})
return (
<div>
<h1>Simple Form Example</h1>
{/* A pre-bound form component */}
<form.Provider>
<form {...form.getFormProps()}>
<form
onSubmit={(e) => {
e.preventDefault()
e.stopPropagation()
void form.handleSubmit()
}}
>
<div>
{/* A type-safe and pre-bound field component*/}
<form.Field
name="firstName"
onChange={(value) =>
!value
? "A first name is required"
? 'A first name is required'
: value.length < 3
? "First name must be at least 3 characters"
? 'First name must be at least 3 characters'
: undefined
}
onChangeAsyncDebounceMs={500}
onChangeAsync={async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
await new Promise((resolve) => setTimeout(resolve, 1000))
return (
value.includes("error") && 'No "error" allowed in first name'
);
value.includes('error') && 'No "error" allowed in first name'
)
}}
children={(field) => {
// Avoid hasty abstractions. Render props are great!
@@ -90,7 +96,7 @@ export default function App() {
<input name={field.name} {...field.getInputProps()} />
<FieldInfo field={field} />
</>
);
)
}}
/>
</div>
@@ -110,19 +116,19 @@ export default function App() {
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? "..." : "Submit"}
{isSubmitting ? '...' : 'Submit'}
</button>
)}
/>
</form>
</form.Provider>
</div>
);
)
}
const rootElement = document.getElementById("root")!;
const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<App />);
ReactDOM.createRoot(rootElement).render(<App />)
```
## You talked me into it, so what now?

View File

@@ -35,7 +35,13 @@ export default function App() {
<h1>Simple Form Example</h1>
{/* A pre-bound form component */}
<form.Provider>
<form {...form.getFormProps()}>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
void form.handleSubmit();
}}
>
<div>
{/* A type-safe and pre-bound field component*/}
<form.Field

View File

@@ -4,16 +4,6 @@ import type { DeepKeys, DeepValue, Updater } from './utils'
import { functionalUpdate, getBy, setBy } from './utils'
import type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'
export interface Register {
// FormSubmitEvent
}
export type FormSubmitEvent = Register extends {
FormSubmitEvent: infer E
}
? E
: Event
export type FormOptions<TData> = {
defaultValues?: TData
defaultState?: Partial<FormState<TData>>
@@ -223,12 +213,7 @@ export class FormApi<TFormData> {
return Promise.all(fieldValidationPromises)
}
// validateForm = async () => {}
handleSubmit = async (e: FormSubmitEvent) => {
e.preventDefault()
e.stopPropagation()
handleSubmit = async () => {
// Check to see that the form and all fields have been touched
// If they have not, touch them all and run validation
// Run form validation
@@ -236,7 +221,7 @@ export class FormApi<TFormData> {
this.store.setState((old) => ({
...old,
// Submittion attempts mark the form as not submitted
// Submission attempts mark the form as not submitted
isSubmitted: false,
// Count submission attempts
submissionAttempts: old.submissionAttempts + 1,

View File

@@ -22,7 +22,6 @@ export type {
export { FormApi, FieldApi, functionalUpdate } from '@tanstack/form-core'
export type { FormProps } from './useForm'
export { useForm } from './useForm'
export type { UseField, FieldComponent } from './useField'

View File

@@ -6,17 +6,10 @@ import React from 'react'
import { type UseField, type FieldComponent, Field, useField } from './useField'
import { formContext } from './formContext'
export type FormSubmitEvent = React.FormEvent<HTMLFormElement>
declare module '@tanstack/form-core' {
interface Register {
FormSubmitEvent: FormSubmitEvent
}
// eslint-disable-next-line no-shadow
interface FormApi<TFormData> {
Provider: (props: { children: any }) => any
getFormProps: () => FormProps
Field: FieldComponent<TFormData, TFormData>
useField: UseField<TFormData>
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
@@ -31,11 +24,6 @@ declare module '@tanstack/form-core' {
}
}
export type FormProps = {
onSubmit: (e: FormSubmitEvent) => void
disabled: boolean
}
export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
const [formApi] = React.useState(() => {
// @ts-ignore
@@ -45,12 +33,6 @@ export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
api.Provider = (props) => (
<formContext.Provider {...props} value={{ formApi: api }} />
)
api.getFormProps = () => {
return {
onSubmit: formApi.handleSubmit,
disabled: api.state.isSubmitting,
}
}
api.Field = Field as any
api.useField = useField as any
api.useStore = (

View File

@@ -12,7 +12,7 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"lib": ["ES2020"],
"module": "ES2020",
"moduleResolution": "node",
"noImplicitAny": true,