admin管理员组

文章数量:1294715

I have two ponents: ParentComponent and ChildComponent.

The ChildComponent has an input[type="text"] element that when it changes its text that event is propagated to the ParentComponent through the event change and the onChange listener.

The code below is a simplification of a bigger problem, that's why you will see some requirements highlighted there.

My problem is that I need to trigger the change event inside the function: handleClick. I did some experiments with no luck.

Here you have the code sandbox you can experiment with (please provide a fork with your approach):

Here you have the code:

ParentComponent.js

import React from "react";
import ChildComponent from "./ChildComponent";

export default class ParentComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "Peter"
    };
  }
  handleChange = event => {
    let target = event.target;
    let value = target.value;
    this.setState({
      name: value
    });
  };
  render() {
    return (
      <div>
        <ChildComponent value={this.state.name} onChange={this.handleChange} /><br />
        <span>Hello</span>&nbsp;
        <span>{this.state.name}!</span>
      </div>
    );
  }
}

ChildComponent.js

import React from "react";
import ReactDOM from "react-dom";

export default class ChildComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.value
    };
  }
  handleChange = event => {
    const name = event.target.value;
    this.setState({ value: name });
    if (this.props.onChange !== undefined) {
      this.props.onChange(event);
    }
  };
  handleClick = name => {
    const inputName = this.refs.name;
    console.log('Name before being changed: ' + inputName.value); // this works
    // PROBABLY HERE IS WHERE THE CODE NEEDS TO BE MODIFIED
    this.setState({ value: name });
    var event = new Event('input', { bubbles: true });
    inputName.dispatchEvent(event); // this doesn't propagate the event to the parent
  };
  render() {
    return (
      <div>
        {"Your name: "}
        <input type="text"
          value={this.state.value}
          onChange={this.handleChange}
          ref="name"
        />
        {/* requirement: the following 2 lines cannot be modified */}
        <button onClick={e => { this.handleClick("Steve"); }}>Steve</button>
        <button onClick={e => { this.handleClick("Emily"); }}>Emily</button>
      </div>
    );
  }
}

Any idea on how to get this working?

Thanks!

I have two ponents: ParentComponent and ChildComponent.

The ChildComponent has an input[type="text"] element that when it changes its text that event is propagated to the ParentComponent through the event change and the onChange listener.

The code below is a simplification of a bigger problem, that's why you will see some requirements highlighted there.

My problem is that I need to trigger the change event inside the function: handleClick. I did some experiments with no luck.

Here you have the code sandbox you can experiment with (please provide a fork with your approach):

https://codesandbox.io/s/wqw49j5krw

Here you have the code:

ParentComponent.js

import React from "react";
import ChildComponent from "./ChildComponent";

export default class ParentComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "Peter"
    };
  }
  handleChange = event => {
    let target = event.target;
    let value = target.value;
    this.setState({
      name: value
    });
  };
  render() {
    return (
      <div>
        <ChildComponent value={this.state.name} onChange={this.handleChange} /><br />
        <span>Hello</span>&nbsp;
        <span>{this.state.name}!</span>
      </div>
    );
  }
}

ChildComponent.js

import React from "react";
import ReactDOM from "react-dom";

export default class ChildComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.value
    };
  }
  handleChange = event => {
    const name = event.target.value;
    this.setState({ value: name });
    if (this.props.onChange !== undefined) {
      this.props.onChange(event);
    }
  };
  handleClick = name => {
    const inputName = this.refs.name;
    console.log('Name before being changed: ' + inputName.value); // this works
    // PROBABLY HERE IS WHERE THE CODE NEEDS TO BE MODIFIED
    this.setState({ value: name });
    var event = new Event('input', { bubbles: true });
    inputName.dispatchEvent(event); // this doesn't propagate the event to the parent
  };
  render() {
    return (
      <div>
        {"Your name: "}
        <input type="text"
          value={this.state.value}
          onChange={this.handleChange}
          ref="name"
        />
        {/* requirement: the following 2 lines cannot be modified */}
        <button onClick={e => { this.handleClick("Steve"); }}>Steve</button>
        <button onClick={e => { this.handleClick("Emily"); }}>Emily</button>
      </div>
    );
  }
}

Any idea on how to get this working?

Thanks!

Share Improve this question edited Dec 28, 2018 at 5:36 Viewsonic asked Dec 28, 2018 at 5:26 ViewsonicViewsonic 9473 gold badges17 silver badges39 bronze badges 6
  • Your sandbox link is working, what you want to do actually? – Just code Commented Dec 28, 2018 at 5:29
  • when you click the buttons: Steve / Emily the name on the ParentComponent doesn't get updated – Viewsonic Commented Dec 28, 2018 at 5:31
  • Check this stackoverflow./questions/23892547/… – Praveen Rao Chavan.G Commented Dec 28, 2018 at 5:37
  • @Justcode the parent ponent don't get the text underneath updated when on the child ponent you click the buttons: Steve / Emily. I need the event gets passed to the parent ponent. – Viewsonic Commented Dec 28, 2018 at 5:43
  • @PraveenRaoChavan.G I tried the approach there but didn't work, here is my try: codesandbox.io/s/1q3mpkmrnl. Could you provide some fork of the code on codesandbox.io? – Viewsonic Commented Dec 28, 2018 at 5:44
 |  Show 1 more ment

4 Answers 4

Reset to default 9

You are missing the track of the input change,

Because React tracks when you set the value property on an input to keep track of the node's value. When you dispatch a change event, it checks it's last value against the current value and if they're the same it does not call any event handlers (as no change has taken place as far as react is concerned). So we have to set the value in a way that React's value setter function will not be called, which is where the setNativeValue es into play.

Here you are setting the state instead of changing the input's value directly so, it will not get the updated value when you are dispatching the event. and if you write value directly like input.value it can not track the changes of the input.

so, you should set the value and dispatch the event, this way you can have the updated value when event is dispatched.

Here is the link of the reference and another, there are other ways too, to fire the change event.

Here is the function you need to set the property so that react can track the changes,

  handleClick = name => {
    const inputName = this.refs.name;
    console.log("Name before being changed: " + inputName.value); // this works

    var event = new Event("input", { bubbles: true });

    this.setNativeValue(inputName, name);
    inputName.dispatchEvent(event);
  };

  setNativeValue = (element, value) => {
    const valueSetter = Object.getOwnPropertyDescriptor(element, "value").set;
    const prototype = Object.getPrototypeOf(element);
    const prototypeValueSetter = Object.getOwnPropertyDescriptor(
      prototype,
      "value"
    ).set;

    if (valueSetter && valueSetter !== prototypeValueSetter) {
      prototypeValueSetter.call(element, value);
    } else {
      valueSetter.call(element, value);
    }
  };

Demo

You can include an onClick function to the parent ponent to change the state and pass it onto the child ponent. In the child ponent you can call the onClick method passed down via props and pass the name when button is clicked.

You can find the example code in the link provided below.

https://codesandbox.io/s/k0n1j2rrx7

I corrected your code like that: in handleChange function of parentComponent I changed the parameter to value from event. In childComponent I added the function call below to handleClick function:

 this.props.onChange(name);

Why I did these changes because, you call your parentComponent's handleChange function from your childComponent' s onChange function. When you click the button, it calls handleClick function. In handleClick function it calls property onChange function. The props.onChange function calls handleChange function of parent ponent. handleClick -> this.props.onChange(name) -> this.handleChange(name) I hope it helps.

If I understood correctly, you are trying to change the parent text like Hello Peter when you click the button from child ponent.

Check my codesandbox : codesandbox

Changes:

In child ponent, pass a props like this.props.onClick(name);

In parent, get it like

  handleClick = name => {
    this.setState({
      name
    });
  };

Hope this is will help you.

本文标签: javascriptReactCannot dispatch onChange event from input text element programaticallyStack Overflow