1
\$\begingroup\$

I'm learning React recently, but I've been having some issues regarding propagating data from component to component. My general situation is: I have a textarea for input, a send button and a textarea for output - essentially a chat interface. So I would like the user to enter data in the first textarea and then propagate it to the next textarea when the button is pressed. I have achieved the result using four components:

//chatbox.js
import React from "react";
import { TextBubble } from "./TextBubble";

const style = {
  border: "2px solid gray",
  width: "400px",
  height: "300px",
  marginTop: "50px",
  overflow: "hidden",
  whiteSpace: "pre"
}

export class Chatbox extends React.Component {
  render() {
    return (
      <p style={style}>
        {this.props.text}
      </p>
    )
  }
}
//InputBar.js
import React from "react";
import { TextEnter } from "./TextEnter.js";
import { SendButton } from "./SendButton.js";

export class InputBar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {text: ''}
    this.setTextInput = this.setTextInput.bind(this)
    this.clickButton = this.clickButton.bind(this)
  }
  setTextInput(text) {
    this.state.text = text
  }
  clickButton() {
    this.props.setTextInput(this.state.text)
  }
  render() {
    var inline ={
      display: "flex"
    }
    return (
      <div style={inline}>
        <TextEnter style={inline} setTextInput={this.setTextInput}/>
        <SendButton style={inline} clickButton={this.clickButton}/>
      </div>
    )
  }
}
//SendButton.js
import React from "react";

export class SendButton extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.props.clickButton()
  }
  render() {
    var style = {
      "background-color": "navy",
      "border": "none",
      "color": "white",
      "width": "50px",
      "padding": "8px 0px",
      "height": "40px",
      "text-align": "center",
      "text-decoration": "none",
      "display": "inline-block",
      "font-size": "16px",
    }
    return (
      <button style={style} onClick={this.handleClick}>
        Send
      </button>
    )
  }
}
//TextEnter.js
import React from "react";

const style = {
  border: "2px solid gray",
  width: "350px",
  height: "40px",
  resize: "none"
}

export class TextEnter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''}
    this.handleChange = this.handleChange.bind(this)
  }
  handleChange() {
    this.setState({value: event.target.value});
    this.props.setTextInput(event.target.value)
  }
  render() {
    return (
      <div>
        <textarea value={this.state.value} onChange={this.handleChange} style={style}></textarea>
      </div>
    )
  }
}

And in App.js, I have

import React from 'react';
import './App.css';

import { Chatbox } from "./components/Chatbox";
import { InputBar } from "./components/InputBar";

export class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {text: ''}
    this.setTextInput = this.setTextInput.bind(this)
  }
  setTextInput(text) {
    var currentText = this.state.text
    if (currentText == '') {
      var newText = text
    } else {
      var newText = currentText + '\n' + text
    }
    this.setState({text: newText})
  }
  render() {
    return (
      <div className="container">
        <div className="row">
          <div>
            <Chatbox text={this.state.text}/>
          </div>
        </div>
        <div className="row">
          <InputBar setTextInput={this.setTextInput}/>
        </div>
      </div>
    );
  }
}

The general strategy here, which I found on some blog post, is to get the data from child to parent by passing the child a function which it calls whenever there is an update - either text in the box changing or the button being pressed. This data can then be passed from parent to child via props. My issue with this is that it seems to take a whoooole lot of boiler plate code which I feel could be somehow reduced, though I'm not sure how to do that.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.