简体   繁体   中英

Convert <Class Component> to <Stateless Functional Component> using Hooks with a callback function

I am trying to convert Class Component to Stateless Functional Component using React Hooks concept

I am working with react-jsonschema-form - Custom field components reference link

const schema = {
  type: "object",
  required: ["lat", "lon"],
  properties: {
    lat: {type: "number"},
    lon: {type: "number"}
  }
};

// Define a custom component for handling the root position object
class GeoPosition extends React.Component {
  constructor(props) {
    super(props);
    this.state = {...props.formData};
  }

  onChange(name) {
    return (event) => {
      this.setState({
        [name]: parseFloat(event.target.value)
      }, () => this.props.onChange(this.state));
    };
  }

  render() {
    const {lat, lon} = this.state;
    return (
      <div>
        <input type="number" value={lat} onChange={this.onChange("lat")} />
        <input type="number" value={lon} onChange={this.onChange("lon")} />
      </div>
    );
  }
}

// Define the custom field component to use for the root object
const uiSchema = {"ui:field": "geo"};

// Define the custom field components to register; here our "geo"
// custom field component
const fields = {geo: GeoPosition};

// Render the form with all the properties we just defined passed
// as props
render((
  <Form
    schema={schema}
    uiSchema={uiSchema}
    fields={fields} />
), document.getElementById("app"));

I am converting the above code like this.

function GeoPosition(props) {
  const [state, setState] = React.useState({ ...props.formData });

  const onChange = name => {
    return event => {
      setState(
        {
          [name]: parseFloat(event.target.value)
        },
        () => props.onChange(state) // GETTING ERROR - UNABLE TO USE CALLBACK
      );
    };
  };

  const { lat, lon } = state;
  return (
    <div>
      <input type="number" value={lat} onChange={onChange("lat")} />
      <input type="number" value={lon} onChange={onChange("lon")} />
    </div>
  );
}

It throws an error, I think, I need to use React.useEffect(), but don't how to implement it. kindly any react experts support.

index.js:1375 Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().

The setter function from useState does not accept a second argument: [hooks] useState - "setState" callback . I'm not sure you need to use useEffect here, you can just call props.onChange(state) after setting the state values. Also note that you need to concat the existing state with the new state values because setState will overwrite existing state.

const onChange = name => {
    return event => {
      setState(state => {
          ...state,
          [name]: parseFloat(event.target.value)
        })
       props.onChange(state);
    };
  };

If you really need to make sure props.onChange is called only after the new value has been set on the current component's state, you can track the state in useEffect, altho you'll need to use a custom function for deep comparison: react useEffect comparing objects

useEffect(() => {
   props.onChange(state);
}, [deepCompare(state)]) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM