From 5ccab36e6f5229696f517c5f75690db4fe3947f7 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Thu, 12 Dec 2019 12:14:28 +0100 Subject: [PATCH] Fix deprecated useField documentation closes #4120 --- docs/Inputs.md | 170 +++++++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 70 deletions(-) diff --git a/docs/Inputs.md b/docs/Inputs.md index ff1cddc1444..ace3a33c469 100644 --- a/docs/Inputs.md +++ b/docs/Inputs.md @@ -1269,7 +1269,7 @@ You can find components for react-admin in third-party repositories. ## Writing Your Own Input Component -If you need a more specific input type, you can write it directly in React. You'll have to rely on react-final-form's [``](https://github.com/final-form/react-final-form#field--reactcomponenttypefieldprops) component, or its [`useField`](https://github.com/final-form/react-final-form#usefield) hook, so as to handle the value update cycle. +If you need a more specific input type, you can write it directly in React. You'll have to rely on react-final-form's [``](https://final-form.org/docs/react-final-form/api/Field) component, or its [`useField`](https://final-form.org/docs/react-final-form/api/useField) hook, so as to handle the value update cycle. For instance, let's write a component to edit the latitude and longitude of the current record: @@ -1304,7 +1304,7 @@ const ItemEdit = (props) => ( ``` -**Tip**: The `` component supports dot notation in the `name` prop, to allow binding to nested values: +**Tip**: React-final-form's `` component supports dot notation in the `name` prop, to allow binding to nested values: ```jsx const LatLongInput = () => ( @@ -1345,107 +1345,137 @@ Now the component will render with a label: ``` -Instead of HTML `input` elements, you can use a material-ui component. To compose material-ui and `Field`, use a [field renderer function](https://github.com/final-form/react-final-form#render-props-fieldrenderprops--reactnode) to map the props: +Instead of HTML `input` elements, you can use a material-ui component like `TextField`. To bind material-ui components to the form values, use the `useField()` hook: ```jsx // in LatLongInput.js import TextField from '@material-ui/core/TextField'; -import { Field } from 'react-final-form'; -const renderTextField = ({ input, label, meta: { touched, error }, ...custom }) => ( - -); +import { useField } from 'react-final-form'; + +const BoundedTextField = ({ name, label }) => { + const { + input: { onChange }, + meta: { touched, error } + } = useField(name); + return ( + + ); +}; const LatLngInput = () => ( - +   - + ); ``` -Material-ui's `` component already includes a label, so you don't need to use `` in this case. `` injects two props to its child component: `input` and `meta`. To learn more about these props, please refer to [the `` component documentation](https://github.com/final-form/react-final-form#fieldrenderprops) in the react-final-form documentation. +**Tip**: Material-ui's `` component already includes a label, so you don't need to use `` in this case. -**Tip**: If you only need one `` component in a custom input, you can let react-admin do the `` decoration for you by using the `addField` Higher-order component: - -```jsx -// in SexInput.js -import SelectField from '@material-ui/core/SelectField'; -import MenuItem from '@material-ui/core/MenuItem'; -import { addField } from 'react-admin'; - -const SexInput = ({ input, meta: { touched, error } }) => ( - - - - -); -export default addField(SexInput); // decorate with react-final-form's +`useField()` returns two values: `input` and `meta`. To learn more about these props, please refer to [the `useField()` hook documentation](https://final-form.org/docs/react-final-form/api/useField) in the react-final-form website. -// equivalent of -import SelectField from '@material-ui/core/SelectField'; -import MenuItem from '@material-ui/core/MenuItem'; -import { Field } from 'react-final-form'; +Instead of HTML `input` elements or material-ui components, you can use react-admin input components, like `` for instance. React-admin components already use `useField()`, and already include a label, so you don't need either `useField()` or `` when using them: -const renderSexInput = ({ input, meta: { touched, error } }) => ( - - - - +```jsx +// in LatLongInput.js +import { NumberInput } from 'react-admin'; +const LatLngInput = () => ( + + +   + + ); -const SexInput = ({ source }) => -export default SexInput; +export default LatLngInput; ``` -**Tip**: `addField` takes a list of props as second argument, so you can set `` props there. It's useful for instance if you need to set the [`format`](https://github.com/final-form/react-final-form#format-value-any-name-string--any) and [`parse`](https://github.com/final-form/react-final-form#parse-value-any-name-string--any) props of the field: - -```jsx -const parse = value => // ... -const format = value => // ... - -const MyDateInput = props => // ... +## `useInput()` Hook -export default addField(MyDateInput, { parse, format }); -``` +React-admin adds functionality to react-final-form: -For more details on how to use react-final-form's `` component, please refer to [the react-final-form doc](https://github.com/final-form/react-final-form#field--reactcomponenttypefieldprops). +- handling of custom event emitters like `onChange`, +- support for an array of validators, +- detection of required fields to add an asterisk to the field label. -Instead of HTML `input` elements or material-ui components, you can use react-admin input components, like `` for instance. React-admin components are already decorated by ``, and already include a label, so you don't need either `` or `` when using them: +So internally, react-admin components use another hook, which wraps react-final-form's `useField()` hook. It's called `useInput()` ; use it instead of `useField()` to create form inputs that have the exact same API as react-admin Input components: ```jsx // in LatLongInput.js -import { NumberInput } from 'react-admin'; +import TextField from '@material-ui/core/TextField'; +import { useInput, required } from 'react-admin'; + +const BoundedTextField = props => { + const { + input: { name, onChange }, + meta: { touched, error }, + isRequired + } = useInput(props); + return ( + + ); +}; const LatLngInput = () => ( - +   - + ); -export default LatLngInput; +``` -// in ItemEdit.js -const ItemEdit = (props) => ( +Here is another example, this time using a material-ui `SelectField` component: + +```jsx +// in SexInput.js +import SelectField from '@material-ui/core/SelectField'; +import MenuItem from '@material-ui/core/MenuItem'; +import { useInput } from 'react-admin'; + +const SexInput = () => { + const { input, meta: { touched, error } } = useInput(props) + return ( + + + + + ); +}; +export default SexInput; +``` + +**Tip**: `useInput` accepts all arguments that you can pass to `useField`. That means that components using `useInput` accept props like [`format`](https://final-form.org/docs/react-final-form/types/FieldProps#format) and [`parse`](https://final-form.org/docs/react-final-form/types/FieldProps#parse), to convert values from the form to the input, and vice-versa: + +```jsx +const parse = value => // ... +const format = value => // ... + +const PersonEdit = props => ( - - + formValue === 0 ? 'M' : 'F'} + parse={inputValue => inputValue === 'M' ? 0 : 1} + /> -); +) ``` ## Linking Two Inputs