'REACT - Attach event handler to children

I'm trying to create a Form component in react, kind of like Formik, but way simpler.

The way I'm thinking involves adding a onChange handler to all the children. I am doing this with children.map(). It works, however I get a key warning

Warning: Each child in a list should have a unique "key" prop.

I know there's no way to suppress this, so maybe there's a better approach to create this Form component? Also, how should I approach the case when the <input> is not a direct child?

Edit: I know how to avoid the problem, I mainly want the best way to approach this, including cases of nested inputs.

Here is how I want to use it:

<Form>
  <label htmlFor="owner">Owner</label>
  <input
    type="text"
    name="owner"
    id="owner"
  />
  <label htmlFor="description">Description</label>
  <input
    type="text"
    name="description"
    id="description"
  />
  <input
    type="submit"
    value="Submit"
  />
</Form>

and here is my code:

import React from 'react';
    
class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {}
    this.handleInputChange = this.handleInputChange.bind(this);
  }
    
  handleInputChange(event) {
    const target = event.target;
    const value =
      target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    console.log(`${name} : ${value}`)
    this.setState({
      [name]: value
    });
  }
    
  render() {
    return (
      <form>
        {this.props.children.map((child) => {
          if (child.type === "input") {
            return (
              <input
                onChange={this.handleInputChange}
                {...child.props}
              />
            )
          }
        })}
      </form>
    )
  }
}
    
export default Form;


Solution 1:[1]

i think this is what you need, already you could add child index as key since there order won't change, and reduce here is not returning null in the array in case the type of the child is not input, map+filter could resolve it also:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.handleInputChange = this.handleInputChange.bind(this);
    // this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;
    console.log(`${name} : ${value}`);
    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        {this.props.children.reduce((childrenAcc, child, index) => {
          if (child.type === "input") {
            return [
              ...childrenAcc,
              <input
                key={index}
                onChange={this.handleInputChange}
                {...child.props}
              />
            ];
          }
          return childrenAcc;
        }, [])}
      </form>
    );
  }
}

function App() {
  return (
    <Form>
      <label htmlFor="owner">Owner</label>
      <input type="text" name="owner" />
      <label htmlFor="description">Description</label>
      <input type="text" name="description" />
      <input type="submit" value="Submit" />
    </Form>
  );
}

check this sandbox .

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lafi