Mohamed Sacko
Mohamed Sacko

Reputation: 253

Function components cannot be given refs. Attempts to access this ref will fail in select component

Here I defined a select component, and I wanted to display it if a condition is true. This select field appears when one of the values ​​of the previous select input is selected. But here is when the new select field (i.e. my select component), and I choose a value from this select, this value is not submitted by my form, and is not present in my data when I do a console log after submitting my form, but the name of the value field is there, but not the value. And i have a warning in my console stating: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of Controller

My Select Component

export const SelectCompanyField = () => {
    // const [page, setPage] = useState(1);
    // const [perPage, setPerPage] = useState(10);
    const { data, error } = useSWR<ServerResponse, any>(companyUrls.base, url => getDataByParams(companyUrls.base));
    console.log("Data", data, "Error", error);
    console.log(data?.entities);


    return (

        <Select

            showSearch
            placeholder="Choisir une compagnie"
            optionFilterProp="children"
            filterOption={(input, option: any) =>
                option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
            }
        >
            {data?.entities.map(d => (
                <option value={d.index} key={d.id}  >
                    {d.name}
                </option>
            ))}

        </Select>


    );
};

The select component to display if the condition is true

<Col md={24} lg={24} sm={24}>


                    {firstOptionValue &&
                        <div className="ant-form-item">
                            <label className="label">Compagnie <span className="text-danger">*</span></label>

                            <Controller

                                as={<SelectCompanyField />}
                                name="company"
                                control={control}
                                defaultValue={""}
                                rules={{ required: false }}

                            {errors.company && "Company is required"}
                        </div>

                    }
                </Col>

The console log of my data submit

{
    "firstName": "Atom",
    "lastName": "Proton",
    "username": "[email protected]",
    "password": "00789",
    "phoneNumber": "44258569",
    "profile": "ADMIN",
    "userType": "B2B_CLIENT",
    "company": ""
}

The company part with the empty quotes, is the part where it should have the value of the field I chose in my select component. I would just like the selected value of the field or the option, appear in my data so that I can submit my form. Thanks

Upvotes: 7

Views: 47818

Answers (2)

Lucas Basquerotto
Lucas Basquerotto

Reputation: 8041

For anyone with this problem and a component that you can't use ref (because you haven't created the component, can't change it, or it doesn't need a ref prop, or you are using typescript with a generic component and used a different/custom name for the ref prop), you can use the react-hook-form Controller render prop (https://stackoverflow.com/a/69671594/4850646), instead of as, which allows you to customize which props are passed:

Instead of:

<Controller as={<SelectCompanyField />} ... />

You can use:

<Controller render={({ field: { ref, ...field } }) => <SelectCompanyField {...field} />} ... />

Upvotes: 3

Adam Jenkins
Adam Jenkins

Reputation: 55613

SelectCompanyField needs to be:

export const SelectCompanyField = React.forwardRef(() => {
 ...
});

When rendering using Controllers as prop, it passes a ref prop to the as prop. React sees a ref being passed, but you aren't using a forwardRef component.

In addition to this, then you need to actually use the ref (and props) which you don't appear to be doing now in SelectCompanyField that are being provided by Controller.

The docs will help you out

☝️ Please read the docs, but your SelectCompanyField receives props like this:

export const SelectCompanyField = React.forwardRef(({field,meta}) => {
   const { onChange, onBlur, value, ref } = field

   return <Select onChange={onChange} value={value} .../>
});

It Is your job to add the onChange handler and the value to the Select component you are rendering. I don't know what Select component it is - is it frame a component framework? is it just a regular select? - so I can't tell you how to do it, but the hook form docs are pretty clear.

Upvotes: 6

Related Questions