简体   繁体   中英

Pass down onChange to child component in react

I have a react component and I want to pass down onChange as a prop to a child component, I'm using atomic design, here's my code:

HeadComponent.js

class Headcomponent extends React.Component{

  constructor (props) {

    super(props);
    this.state = {
      email: '',
      password: '',
      formErrors: {email: '', password: ''},
      emailValid: false,
      passwordValid: false,
      formValid: false,
      items: [],

    }
  }

  handleUserInput = (e) => {

    const name = e.target.name;
    const value = e.target.value;
    this.setState({[name]: value},
                  () => { this.validateField(name, value) });
  }

render(){

    const fields= [
    {
      label: 'hhdghghd',
      placeholder: 'fhfhhfhh 1',
      ExampleMessage: this.state.formErrors.email ,
      ErrorMessage: 'error message for input 1',
      inputValue: this.state.email,
      onChange: this.handleUserInput  //this is where I'm passing my function


    },
    {
      label: 'fffff',
      placeholder: 'tttttt 2',
      ExampleMessage: 'example message  for second label',
      ErrorMessage: 'error message for input 2',
      onChange: this.handleUserInput


    },
  ]

return (
    <div>

  <Form fields={fields} buttonText="Submit"/>

    </div>
        );
    }

}

export default Headcomponent;

Form.js

    const Form = props => (
      <form className="Form">
        {
          props.fields.map((field, i) => (<LabeledInput label={field.label}
           placeholder={field.placeholder}
           ExampleMessage={field.ExampleMessage}
           ErrorMessage={field.ErrorMessage}
           onChange= {(e)=> field.onChange}
           inputValue= {field.inputValue}
           key={i}
           passwordError={props.passwordError}

           />))
        }
        <Button text={props.buttonText} />
      </form>
    );

    Form.propTypes = {
      fields: PropTypes.arrayOf(PropTypes.object).isRequired,
      buttonText: PropTypes.string.isRequired,
    };

    export default Form;

LabeledInput

const LabeledInput = props => (
  <div className={`form-group `} >
    <Label text={props.label} />
    <Input inputValue={props.inputValue} placeholder={props.placeholder} type="text" onChange={(e)=> props.onChange} />

    <ErrorMessage text={props.ErrorMessage} />
    <ExampleMessage ExampleMessage={ props.ExampleMessage} />
  </div>
);

LabeledInput.propTypes = {
  label: PropTypes.string.isRequired,
  placeholder: PropTypes.string,
  onChange: PropTypes.func.isRequired,
  //value: PropTypes.string.isRequired,
  exampleText: PropTypes.string,
};
export default LabeledInput;

Input.js

const Input = props => (
  <input type={props.type} class="form-control form-control-success is-valid" placeholder={props.placeholder} value={props.inputValue} className="form-control form-control-success"
      onChange={ (e)=> props.onChange } />
);

Input.propTypes = {

  inputValue: PropTypes.string,
  type: PropTypes.string,
  placeholder: PropTypes.string,
  onChange: PropTypes.func.isRequired,
};

export default Input;

How to pass handleUserInput from HeadComponent.js down to Input.js , so far using props I can't get it to trigger while changing text.

You forgot to actually call field.onChange method. Instead of :

onChange= {(e)=> field.onChange}

You can change it to:

onChange= {field.onChange}

I also noticed that your handleUserInput set state at :

{ [name]: e.target.value }

However, you are not setting name to any of the inputs and that's not gonna work.

Please have a look at my working sample:

 const LabeledInput = props => ( <div className="form-group"> <label>{props.label}</label> <input className="form-control" type="text" placeholder={props.placeholder} onChange={props.onChange} // That's how you have to call onChange name={props.name} // You are not setting this prop /> <div>{props.ErrorMessage}</div> <div>{props.ExampleMessage}</div> </div> ) const Form = ({ buttonText, fields }) => ( <form className="Form"> {fields.map((field, i) => <LabeledInput key={i} {...field} />)} <button className="btn btn-primary">{buttonText}</button> </form> ) class Headcomponent extends React.Component { constructor() { super() this.state = { email: '', password: '', formErrors: {email: '', password: ''}, emailValid: false, passwordValid: false, formValid: false, items: [], } this.handleUserInput = this.handleUserInput.bind(this) } handleUserInput(e) { const name = e.target.name const value = e.target.value // Now that you have `name` and `value`, state updates are going to work this.setState({ [name]: value }) } render() { const fields = [ { label: 'Email', placeholder: 'email placeholder', ExampleMessage: this.state.formErrors.email , ErrorMessage: 'error message for input 1', inputValue: this.state.email, onChange: this.handleUserInput, name: 'email', }, { label: 'Password', placeholder: 'password placeholder', ExampleMessage: 'example message for second label', ErrorMessage: 'error message for input 2', onChange: this.handleUserInput, name: 'password', }, ] return ( <div> <Form fields={fields} buttonText="Submit"/> <div style={{ marginTop: 20 }}> <div>state.email: {this.state.email}</div> <div>state.password: {this.state.password}</div> </div> </div> ) } } ReactDOM.render( <Headcomponent />, document.getElementById('root') ) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <div id="root"></div> 

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