2

I am trying to do something like Hello World, but I want the user to be able to enter their first and last name, and then on the parent, it will say Hello, [FirstName] [LastName]!

Needless to say I'm pretty new to React, but I wanted to have a separate component specifically for entering the names.

App.js (parent)

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import InsertName from "./insertName";

class App extends Component {
  state = {
    name: ""
  };
  handleClick = props=> {
    console.log("heyy", props.fname);
  };
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
      <h1 className="App-title">Welcome to React {this.state.name}</h1>
    </header>
    <p className="App-intro">
      To get started, editLdOL <code>src/App.js</code> and save to reload.
    </p>
    <InsertName onClick={this.handleClick} />
  </div>
);
  }
}

export default App;

Child, InsertName

import React, { Component } from "react";
class InsertName extends Component {
 render() {
return (
  <div>
    First name: <input type="text" name="fname" value={this.props.fName} />
    <br />
    Last name: <input type="text" name="lname" value={this.props.lName} />
    <br />
    <button onClick={this.props.onClick}>Click here!!</button>
  </div>
);
  }
}

export default InsertName;

3 Answers 3

3

In App.js (parent)

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import InsertName from "./insertName";

    class App extends Component {
      state = {
        lName: '',
        fName: ''
      };
      handleClick = props=> {
        const {lName, fName} = this.state
        //Handle fName and lName here
      };
      onLNameChange = (e) => {
        this.setState({lName: e.target.value})
      }
      onFNameChange = (e) => {
        this.setState({fName: e.target.value})
      }
      render() {
        const {fName, lName} = this.state
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React {this.state.name}</h1>
        </header>
        <p className="App-intro">
          To get started, editLdOL <code>src/App.js</code> and save to reload.
        </p>
        <InsertName onLNameChange={this.onLNameChange} onFNameChange={this.onFNameChange} onClick={this.handleClick} fName={fName} lName={lName} />
      </div>
    );
      }
    }

    export default App;

In InsertName component:

import React, { Component } from "react";
class InsertName extends Component {
 render() {
return (
  <div>
    First name: <input type="text" name="fname" onChange={this.props.onFNameChange} value={this.props.fName} />
    <br />
    Last name: <input type="text" name="lname" onChange={this.props.onLNameChange} value={this.props.lName} />
    <br />
    <button onClick={this.props.onClick}>Click here!!</button>
  </div>
);
  }
}

export default InsertName;
Sign up to request clarification or add additional context in comments.

4 Comments

When passing the functions into the child component, make sure to .bind(this) eg <InsertName onLNameChange={this.onLNameChange} ... Should be <InsertName onLNameChange={this.onLNameChange.bind(this)}
when you declare function as: onLNameChange = (e) => {}, you don't need bind(this). You can try!
my mistake, I didn't notice arrow function.
Quick question, this seems to update automatically as I type. How would I make it so that the name only shows upon clicking the button. Thank you
1

On the parent component, you declare methods that set the first name and last name like:

constructor(){
   this.state = { fname: "", lname: "" };
}

changeFirstName = (newName) => {
   this.setState({ fname: newName });
}

changeLastName = (newName) => {
   this.setState({ lname: newName });
}

handleClick = () => {
   console.log("Hey ", this.state.fname, " ", this.state.lname);
}

Then, pass them to the child component as props:

<InsertName
   onClick={this.handleClick}
   fname={this.state.fname}
   changeFirstName={this.changeFirstName}
   lname={this.state.lname}
   changeLastName={this.changeLastName}
/>

Lastly, access them in your child component like this:

<div>
   First name: <input type="text" name="fname" value={this.props.fname} onChange={(event) => this.props.changeFirstName(event.target.value)} />
   <br />
   Last name: <input type="text" name="lname" value={this.props.lName} onChange={(event) => this.props.changeLastName(event.target.value)} />
   <br />
   <button onClick={this.props.onClick}>Click here!!</button>
</div>

Comments

0

What you asked here actually a pretty common and standard way of changing inputs via a child component. You will keep your state in the parent component, pass some of the pieces of this state and your handler functions to your child component then update the state.

  • The child component can be and most of the time should be a stateless, dumb component. Because there is no need for the state or a lifecycle method.
  • Your inputs are controlled. This means there is a change handler to update your state and they are getting the value from the state again.
  • You can change the inputs in one handler function by names.

The rest is in the comments :) By the way if you don't look the official documentation, I strongly suggest you do that first.

class App extends React.Component {
  state = {
    firstName: "",
    lastName: "",
    name: ""
  };

  handleClick = () => {
    const { firstName, lastName } = this.state;
    // We create our name then update our state.
    const name = `${firstName} ${lastName}`;
    this.setState({ name });
  };

  // One handler function to update the state.
  // Using computed property names feature we can use
  // variables for an object key like [name]

  handleChange = e => {
    // Destructuring values from e.target.
    const { name, value } = e.target;
    this.setState({ [name]: value });
  };

  render() {
    const { firstName, lastName, name } = this.state;
    return (
      <div>
        {/* A small condition check for our welcome. If there isn't any
        firstName or lastName, then we render "anonymous". */}
        <h1>
          Welcome,
          {!name ? " anonymous" : name}
        </h1>
        {/* Here, we are passing onClick and onChange handlers. Also our related state pieces. */}
        <InsertName
          firstName={firstName}
          lastName={lastName}
          onClick={this.handleClick}
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

const InsertName = props => {
  // More destructuring.
  const { firstName, lastName, onClick, onChange } = props;

  return (
    // One onChange handler for each input.
    // Also, input names should match with the state names.
    <div>
      First name:{" "}
      <input
        type="text"
        name="firstName"
        value={firstName}
        onChange={onChange}
      />
      <br />
      Last name:{" "}
      <input type="text" name="lastName" value={lastName} onChange={onChange} />
      <br />
      <button onClick={onClick}>Click here!!</button>
    </div>
  );
};


ReactDOM.render(<App />, 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>
<div id="root"></div>

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.