Perplexityy
Perplexityy

Reputation: 569

React: Updating form on button click

I have three components, App, TextBox and Keyboard.

What I am trying to do is:

  1. User clicks on one of the buttons on keyboard.jsx, a child component
  2. Pass the associated character to App.js (this works, via callback functions)
  3. Once a new character has been passed to App.js, update the other child component, TextBox.jsx, by passing it the new value.

However, I am stuck at step 3. I have the value passed to App.js, but I don't know how to pass it to the child component, Keyboard.jsx, so i can update the input form.

Here is my code:

keyboard.jsx

import React, { Component } from "react";

class Keyboard extends Component {
  state = {
    current: null,
    keys: ["á", "é", "í", "ñ", "ó", "ú", "ü"]
  };

  render() {
    return (
      <div>
        <table>
          <tbody>
            {Object(
              this.state.keys.map(key => {
                return (
                  <td>
                    <button
                      onClick={() => {
                        this.solve(key, this.props.handler);
                      }}
                    >
                      {key}
                    </button>
                  </td>
                );
              })
            )}
          </tbody>
        </table>
      </div>
    );
  }
  solve = (char, callback) => {
    this.setState({ current: char });
    callback(char);
    return;
  };
}

export default Keyboard;

textbox.jsx

import React, { Component } from "react";

class TextBox extends Component {
  state = { equation: null };
  render() {
    return (
      <div>
        <form onSubmit={this.mySubmitHandler}>
          <input
            size="35"
            type="text"
            name="equation"
            onChange={this.handleInputChange}
          />
        </form>
      </div>
    );
  }
  handleInputChange = event => {
    event.preventDefault();
    this.setState({
      [event.target.name]: event.target.value
    });
  };

  mySubmitHandler = event => {
    event.preventDefault();
    this.setState({ equation: event.target.value });
    alert("You are submitting " + this.state.equation);
    console.log(this.state.equation);
  };
}

export default TextBox;

App.js

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import Keyboard from "./components/keyboard";
import TextBox from "./components/textbox";

class App extends Component {
  state = { character: null };
  render() {
    return (
      <div>
        <TextBox />
        <Keyboard handler={this.handler} />
      </div>
    );
  }

  handler = arg => {
    console.log(arg);
  };
}

export default App;

Upvotes: 1

Views: 893

Answers (3)

Leo Melin
Leo Melin

Reputation: 234

What I see you are trying to do is to have buttons with certain special letter that you can click to insert them into a input field that is in a separate component.

In this particular case you should implement two-way binding. It'll work like this:

class Keyboard extends React.Component {
  state = {
    current: null,
    keys: ["á", "é", "í", "ñ", "ó", "ú", "ü"]
  };

  render() {
    return (
      <div>
        <table>
          <tbody>
            {Object(
              this.state.keys.map(key => {
                return (
                  <td>
                    <button
                      onClick={() => {
                        this.solve(key, this.props.handler);
                      }}
                    >
                      {key}
                    </button>
                  </td>
                );
              })
            )}
          </tbody>
        </table>
      </div>
    );
  }
  solve = (char, callback) => {
    this.setState({ current: char });
    callback(char);
    return;
  };
}

class TextBox extends React.Component {
  render() {
    return (
      <div>
        <form onSubmit={this.mySubmitHandler}>
          <input
            value={this.props.equation}
            size="35"
            type="text"
            name="equation"
            onChange={this.handleInputChange}
          />
        </form>
      </div>
    );
  }
  handleInputChange = event => {
    event.preventDefault();
    this.setState({
      [event.target.name]: event.target.value
    });
    this.props.equationChange(event.target.value)
  };

  mySubmitHandler = event => {
    event.preventDefault();
    alert("You are submitting " + this.props.equation);
    console.log(this.props.equation);
  };
}

class App extends React.Component {
  state = { character: null };
  render() {
    return (
      <div>
        <TextBox equationChange={this.equationChange} equation={this.state.equation} />
        <Keyboard handler={this.handler} />
      </div>
    );
  }

  handler = arg => {
    console.log(arg);
    this.setState({ equation: (this.state.equation || '') + arg
                  });
  };

  equationChange = equation => {
    this.setState({ equation });
  }
}

React.render(<App />, document.getElementById('app'));

A working codepen: https://codepen.io/leo-melin/pen/mdyEvwQ

Upvotes: 1

Awais Rafiq Chaudhry
Awais Rafiq Chaudhry

Reputation: 490

This can be achieved by passing the state variable character this.state.character to the child component Textbox in App.js, and this.handler method in App.js should update the this.state.character.

class App extends Component {
  state = { character: null };
  render() {
    return (
      <div>
        <TextBox character={this.state.character} />
        <Keyboard handler={this.handler} />
      </div>
    );
  }

  handler = arg => this.setState({ character: arg });
}

Upvotes: 1

Megha A.
Megha A.

Reputation: 11

You can pass this.state.character as prop to textbox and then in textbox.jsx extract character from props i.e const {character} = this.props and then display it in textbox.

Upvotes: 0

Related Questions