Search code examples
javascriptreactjsreact-datepickerunform

Datepicker component breaking an edit screen, using @unform and react-datepicker


I created the following component to select dates in UnForm:

export default function DatePickerInput({ name, ...rest }) {
  const datepickerRef = useRef(null);
  const { fieldName, defaultValue = '', registerField } = useField(name);

  const [date, setDate] = useState(defaultValue || null);
  useEffect(() => {
    registerField({
      name: fieldName,
      ref: datepickerRef.current,
      path: 'props.selected',
    });
  }, [fieldName, registerField]);

  return (
    <Label htmlFor={fieldName}>
      <UnInput>
        <ReactDatePicker
          ref={datepickerRef}
          selected={date}
          onChange={setDate}
          dateFormat="dd/MM/yyyy"
          placeholderText="dd/mm/aaaa"
          writable="true"
          {...rest}
        />
      </UnInput>
    </Label>
  );
}

To save records the component is working normally, loading and saving the date I selected. When I am going to edit a record, when trying to load the date in the initial load, the page is broken and the following error is displayed:

Unhandled Rejection (TypeError): Cannot assign to read only property 'selected' of object '#<Object>'

If I comment out the line path: 'props.selected', in useEffect () the screen is not broken, but the date is not filled in the component. How do it work?


Solution

  • Issue :

    formRef.current.setFieldValue('birthday',value) this will try to set value on provided path , in our case provided path is props.selected.

    And props.selected is read-only property so you can't set value on props hence the error.

    useEffect(() => {
        registerField({
          name: fieldName,
          ref: datepickerRef.current,
          path: 'props.selected', // <---- this is props, and it's readonly
          clearValue: (ref) => {
            ref.clear();
          },
        });
    }, [fieldName, registerField]);
    

    Solution :

    You can remove the path and use getter and setter methods, named as getValue and setValue :

    setValue : to set the initial value or whatever passed from setFieldValue

    getValue : to get value on submit

    useEffect(() => {
        registerField({
          name: fieldName,
          ref: datepickerRef.current,
          clearValue: ref => {
            ref.clear();
          },
          setValue: (e, v) => {
            setDate(new Date(v)); // <---- Setting up default value 
          },
          getValue: () => {
            return datepickerRef.current.props.selected; // to get selected value from Date picker's props
            // OR
            return Date.toString(); // to get selected value from state it self
          }
        });
    }, [fieldName, registerField]);
    

    WORKING DEMO :

    Edit #SO-Datepicker-unform-setvalue