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

2

6

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

Ellsworthellwood answered 13/5, 2021 at 2:37 Comment(1)
A different use case but similar error message: https://mcmap.net/q/127090/-how-do-i-avoid-39-function-components-cannot-be-given-refs-39-when-using-react-router-domIntegrator
S
5

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.

Safire answered 13/5, 2021 at 2:49 Comment(4)
Hi @Adam, with your suggestion the warning has disappeared, but the value of the selected input is not submitted.Ellsworthellwood
@MohamedSacko - See my update, it's clear in the docs - the SelectCompanyField receives the onChange handler and the value from the form, it is your job to plumb those into your component.Safire
My Select is import { Button, Col, Input, Row, Select } from "antd";Ellsworthellwood
@MohamedSacko - then look at the docs for antd to see how to use the component. It looks like you just need to pass the onChange and value props directly to the Select (see my edit). But I've taken you as far as I can, it's time to start reading some docs instead of my answer. If you try stuff and it doesn't work and you aren't sure why, then please come back and ask for help.Safire
F
2

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://mcmap.net/q/1775966/-react-hook-form-as-vs-render-unable-to-understrand-the-syntax-and-how-are-they-same), 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} />} ... />
Fabricate answered 2/2, 2023 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.