React final form - Lauviah0622/Lavi-Note GitHub Wiki

觀念

要記住一個概念,跟原本你在用 html 表單不一樣

在原本的 HTML 的表單裡面,你需要去向 element 裡面狀態 但是在 react 裡面,他的狀態是已經儲存好的,所有的 element 只是一個呈現還有發出 event 的工具而已。

自己覺得 final form 的概念是這樣, 最上層的 form 會監聽 form 的 onChange 事件,然後依照 onchange 去改變 state。然後這樣的 State 再去渲染說 form 裡面的 選項那些要怎麼呈現

底層可能還是要看 source code 有空可以看看

Validate

有兩種不同的驗證方式

  1. field level 也就是每個欄位分別驗證
  2. record level 會對整個表單的值進行驗證

可以利用 error with delay 來延遲顯示錯誤資訊,這樣使用這就不會覺得很煩,一直跳 error https://codesandbox.io/s/react-final-form-synchronous-errors-debounced-forked-g4r28?file=/src/ErrorWithDelay.js

可以利用

  1. 先同步檢查資料
  2. 然後再用 async 做最後檢查

validata 可以 return Promise,如果還在 Pending 的話就會傳送 validating 的 參數給 form

Component API

Form

要在 <Form> 的參數家東西

用 render Props 才會是 純的 html 元素 不會在外面再包一層 JSX。

best Practice 是 用 render Props

不過包一層會比較適合你從 Redux form 班過來(應該是 API 比較像)

render props 的 props 要接收 handleSubmit form HTML 的 onsubmit 也要加上 handleSubmit

form 參數

pristine:沒有輸入過東西就是 true

validate = (value) => error | Promise

submitting

initialValues:放入初始值

initialValues={{ stooge: "larry", employed: false }}

reset,function 可以 reset 內容

Field

使用方法

  1. 加上 field name field name 可以用 object 形式的 string,這樣出來的 result 就會是巢狀 可以用這個 測測看 https://8ypq7n41z0.codesandbox.io/

  2. 用其中一種方式 render

Prop Type
<Field component/> 'input' or 'select' or 'textarea
<Field component/> React.ComponentType
<Field render/> Function
<Field children/> Function
  1. props 串上去 component 裡面

如果是用內建的 input, select 這些,那它會自己幫你串好,你可以直接在 children 裡面放入你的選項

那如果是用 react 內建的 HTML 形式 <input>,可以用 destructure 的方式把 props 放進去

<Field name="myField">
  {(props) => (
    <div>
      <input {...props.input} />
    </div>
  )}
</Field>

Custom Input 就這樣,

<Field name="myField">
  {(props) => (
    <div>
      <TextField
        name={props.input.name}
        value={props.input.value}
        onChange={props.input.onChange}
      />
    </div>
  )}
</Field>

各種形式表格

第一次知道

多選題

type Props = FieldRenderProps<string[], any>;

const MultiSelectInput: React.FC<Props> = ({ input, meta, ...rest }: Props) => (
  <select {...input} {...rest} multiple value={input.value || []} />
);

// 會自動把 children 傳進去

<Field<string[]> name="toppings" component={MultiSelectInput}>
  <option value="chicken">🐓 Chicken</option>
  <option value="ham">🐷 Ham</option>
  <option value="mushrooms">🍄 Mushrooms</option>
  <option value="cheese">🧀 Cheese</option>
  <option value="tuna">🐟 Tuna</option>
  <option value="pineapple">🍍 Pineapple</option>
</Field>

Input

function RadioInput<T extends string>({
  input,
  meta,
  ...rest
}: FieldRenderProps<T, any>) {
  return <input type="radio" {...input} {...rest} />;
}

<label>
  <Field<Stooge>
    name="stooge"
    component={RadioInput}
    type="radio"
    value="larry"
  />{" "}
  Larry
</label>;

hooks

UseField

useField 會把你輸入的 name 的表格欄位內容註冊給你,選擇要註冊哪些欄位,你就可以得到這些欄位的資訊

可以用在 error,像是這樣

const Error = ({ name }) => {
  const {
    meta: { touched, error },
  } = useField(name, { subscription: { touched: true, error: true } });

  console.log(name, touched);
  console.log(name, error);
  return touched && error ? <span>{error}</span> : null;
};

<Error name="firstName" />;

Typescirpt

可以加上 Type 的部份

onsubmit

可以加在 values 的地方,因為所有表單的內容都會從那裡來

但記得沒有初始值的欄位要加上?

type Stooge = "larry" | "moe" | "curly";
interface Values {
  firstName?: string;
  lastName?: string;
  employed: boolean;
  favoriteColor?: string;
  toppings?: string[];
  sauces?: string[];
  stooge: Stooge;
  notes?: string;
}

const onSubmit = async (values: Values) => {
  await sleep(300);
  window.alert(JSON.stringify(values, undefined, 2));
};

Custom Field Component

type Props = FieldRenderProps<string[], any>;

const MultiSelectInput: React.FC<Props> = ({ input, meta, ...rest }: Props) => (
  <select {...input} {...rest} multiple value={input.value || []} />
);
⚠️ **GitHub.com Fallback** ⚠️