1
votes

i try to create functional component on React, Typescript and ant ui. But when i create child component i have warning - "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?". Please tell me where i made mistakes?

CreateCounterpartyComponent:

const CreateCounterpartyComponent: React.FC<FormComponentProps> = props => {
  const GET_ALL = gql`
    query {
      types {
        value: id
        name: full_name
      }
    }
  `;
  const { getFieldDecorator } = props.form;
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    console.log(e);
  };
  const changeHandler = (e:number) => {
    console.log(e)
  }
  const { loading, data } = useQuery(GET_ALL);
  if (loading) return <Loader />;
  return (
    <div>
      <Form onSubmit={handleSubmit}>
        <Form.Item hasFeedback>
          {getFieldDecorator('address', {
            rules: [{ required: true, message: 'Address?' }],
          })(<CustomSeletor items={data.types} width="20%" changeEvent={(e)=>changeHandler(e)}/>)}
        </Form.Item>
        <Form.Item>
          <Button type="primary" htmlType="submit" className="login-form-button">
            Send
          </Button>
        </Form.Item>
      </Form>
    </div>
  );
};

export const CreateCounterparty = Form.create()(CreateCounterpartyComponent);

CustomSeletor:

const { Option } = Select;

interface IProps {
  items: ISelectorProps[];
  width: string;
  changeEvent(e:number):void;
}

export const CustomSeletor: React.FC<IProps> = ({ items, width, changeEvent }) => {
  const mystyles = {
    width: width,
  };
  const handleChange = (e:number) => {
      changeEvent(e)
  }
  const options = items.map(({ value, name }) => <Option key={value} value={value}>{name}</Option>);
  return (
    <Select style={mystyles} onChange={handleChange}>
      {options}
    </Select>
  );
};
1
Are you sure this is the code it's complaining about? I don't see any refs. - T.J. Crowder
Yes, stack: Check the render method of CreateCounterpartyComponent. in CustomSeletor (at CreateCounterparty.tsx:115) in span (created by Context.Consumer) in div (created by Context.Consumer) in div (created by Context.Consumer) - lobs

1 Answers

1
votes

You're using antd. As specified on this page:

Customized or third-party form controls can be used in Form, too. Controls must follow these conventions:

  • It has a controlled property value or other name which is equal to the value of valuePropName.
  • It has event onChange or an event which name is equal to the value of trigger.

antd requires that CustomSelector be able to receive refs. Function components must be wrapped in React.forwardRef in order to receive refs, otherwise you will get the error you see.

The solution is to wrap CustomSelector in forwardRef:

export const CustomSelector = React.forwardRef(({ items, width, changeEvent }, ref) => {
  const mystyles = {
    width: width,
  };
  const handleChange = (e:number) => {
      changeEvent(e)
  }
  const options = items.map(({ value, name }) => <Option key={value} value={value}>{name}</Option>);
  return (
    <Select ref={ref} style={mystyles} onChange={handleChange}>
      {options}
    </Select>
  );
});

You should ensure that Select conforms to the requirements of antd. Check their docs for that as I don't know them.