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 有空可以看看
有兩種不同的驗證方式
- field level 也就是每個欄位分別驗證
- record level 會對整個表單的值進行驗證
可以利用 error with delay 來延遲顯示錯誤資訊,這樣使用這就不會覺得很煩,一直跳 error https://codesandbox.io/s/react-final-form-synchronous-errors-debounced-forked-g4r28?file=/src/ErrorWithDelay.js
可以利用
- 先同步檢查資料
- 然後再用 async 做最後檢查
validata 可以 return Promise,如果還在 Pending 的話就會傳送 validating 的 參數給 form
要在 <Form>
的參數家東西
用 render Props 才會是 純的 html 元素 不會在外面再包一層 JSX。
best Practice 是 用 render Props
不過包一層會比較適合你從 Redux form 班過來(應該是 API 比較像)
render props 的 props 要接收 handleSubmit form HTML 的 onsubmit 也要加上 handleSubmit
pristine:沒有輸入過東西就是 true
validate = (value) => error | Promise
submitting
initialValues:放入初始值
initialValues={{ stooge: "larry", employed: false }}
reset,function 可以 reset 內容
-
加上 field name field name 可以用 object 形式的 string,這樣出來的 result 就會是巢狀 可以用這個 測測看 https://8ypq7n41z0.codesandbox.io/
-
用其中一種方式 render
Prop | Type |
---|---|
<Field component/> |
'input' or 'select' or 'textarea |
<Field component/> |
React.ComponentType |
<Field render/> |
Function |
<Field children/> |
Function |
- 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>
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>;
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" />;
可以加上 Type 的部份
可以加在 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 || []} />
);