1

I'm trying to migrate legacy code-base from class-based to function based using hooks.

The legacy code was like :

constructor(props){
    super(props)
    this.state = {
        pickerProps: {
            onPickDate: this.onPickDate,
            activeColor: "#119955",
            date: "12-12-2012"
        },
        inputStyle: "",
        selectedDate: null
    }
}

onPickDate = date => {
    this.setState((state) => ({
        selectedDate: date
    }))
}

onInputChange = (prop, value) => {
    this.setState((state) => ({ 
        pickerProps: {
            ...state.pickerProps,
            [prop]: value
        }
     }))
} 

changeInputStyle = e => {
    const value = e.target.value
    this.setState((state) => ({inputStyle: value}))
}

and the new code is :

const [inputStyle, setInputStyle] = useState("");
  const [selectedDate, setSelectedDate] = useState(null);
  const [pickerProps, setPickerProps] = useState({
    onPickDate:onPickDate, // How to pass function here
    activeColor: "#119955",
    date: "12-12-2012",
  });

  // This is the function I want to pass to useState()
  const onPickDate = (date) => {
    setSelectedDate(date);
  };

  const onInputChange = (prop, value) => {
    setPickerProps({ [prop]: value });
  };

  const changeInputStyle = (e) => {
    const value = e.target.value;
    setInputStyle(value);
  };

I receive a warning : The onPickDate was used before defined

Also when I send pickerProps to DatePicker :

 <div className="date-picker">
            <DatePicker {...pickerProps} />
          </div>

It invokes an error :

OnPickDate is not defined ()
4
  • Tried moving your onPickDate declaration above the useState ? Commented May 8, 2020 at 7:44
  • Yes, I know the problem is related to hoisting but how can I pass the function without passing it above useState? Commented May 8, 2020 at 7:48
  • 2
    Actually, one should not set the func in state, as the func would be re-created on each re-render unless you are using useCallback. Have not seen patterns of setting func to state. You can use it directly on render, whats the reason to put it in a state.. planning to modify it ?? 🤔 Commented May 8, 2020 at 7:56
  • same as Panther, wondering why you would place a function inside a state, maybe this is also a good time to refactor this ? Commented May 8, 2020 at 8:07

1 Answer 1

2

The problem here is related to function hoisting. The function you have declared is of type const and such variables with const or let declaration are not hoisted.

If you declare the function with function definition it will work without having to write it above useState

const [inputStyle, setInputStyle] = useState("");
  const [selectedDate, setSelectedDate] = useState(null);
  const [pickerProps, setPickerProps] = useState({
    onPickDate:onPickDate, // How to pass function here
    activeColor: "#119955",
    date: "12-12-2012",
  });

  function onPickDate(date) {
    setSelectedDate(date);
  };

  const onInputChange = (prop, value) => {
    setPickerProps({ [prop]: value });
  };

  const changeInputStyle = (e) => {
    const value = e.target.value;
    setInputStyle(value);
  };

However you need to store functions in state as it will make it difficult for you to update state, you can directly pass them as props to children

const [inputStyle, setInputStyle] = useState("");
  const [selectedDate, setSelectedDate] = useState(null);
  const [pickerProps, setPickerProps] = useState({
    activeColor: "#119955",
    date: "12-12-2012",
  });

  // This is the function I want to pass to useState()
  const onPickDate = (date) => {
    setSelectedDate(date);
  };

  const onInputChange = (prop, value) => {
    setPickerProps({ [prop]: value });
  };

  const changeInputStyle = (e) => {
    const value = e.target.value;
    setInputStyle(value);
  };

  return (
       <div className="date-picker"> 
            <DatePicker {...pickerProps} onPickDate ={onPickDate}/>
          </div>
  }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.