4

I have two components: 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!

6
  • Your sandbox link is working, what you want to do actually? Commented Dec 28, 2018 at 5:29
  • when you click the buttons: Steve / Emily the name on the ParentComponent doesn't get updated Commented Dec 28, 2018 at 5:31
  • Check this stackoverflow.com/questions/23892547/… Commented Dec 28, 2018 at 5:37
  • @Justcode the parent component don't get the text underneath updated when on the child component you click the buttons: Steve / Emily. I need the event gets passed to the parent component. 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? Commented Dec 28, 2018 at 5:44

4 Answers 4

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 comes 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

Sign up to request clarification or add additional context in comments.

Comments

0

You can include an onClick function to the parent component to change the state and pass it onto the child component. In the child component 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

Comments

0

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 component. handleClick -> this.props.onChange(name) -> this.handleChange(name) I hope it helps.

Comments

-1

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

Check my codesandbox : codesandbox

Changes:

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

In parent, get it like

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

Hope this is will help you.

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.