1

Relatively new to React here, so forgive me if this is an easy fix.

I have a component that has a form - this form has 4 choices, and my intention is that every time you click an option on the form, a child component is rendered with data from the choice selected.

Here is the issue I am having. Currently, I'm able to load the child component upon my first choice selection, but I cannot reload the component unless I select the default value first.

Attached is my code: App.js; here is the codesandbox: https://codesandbox.io/s/blissful-agnesi-1wo7s

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class App extends Component  {
    constructor(props)  {
        super(props);

        this.state = { 
          value: '',
          prevValue: '',
          submitted: false
        }; 
        
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        this.setState({prevValue: this.state.value});
        this.setState({value: event.target.value});
        this.setState({submitted: true});
        event.preventDefault();
    }

    render()    {  
        var renderingBool = false;

        if (this.state.submitted)   {
            if (this.state.value !== "--")   {
                renderingBool = true;
            }
        }

        return (
            <div className="Base">
                <h1> By Productline </h1>
                <form>
                    <label className="label">
                        Select Workflow: {"               "}
                        <select value={this.state.value} onChange={this.handleChange}>
                            <option value="--"> -- </option>
                            <option value="test1">test1</option>
                            <option value="test2">test2</option>
                            <option value="test3">test3</option>
                        </select>
                    </label>
                </form>

                <div>
                    {renderingBool && <ChildComponent history={this.props.history} detail={this.state.value}/>}
                </div>
            </div>
        );
    }
}

export default App;

ChildComponent.js

import React, {Component} from 'react';

class ChildComponent extends Component{
  constructor(props)  {
    super(props);

    this.input = props.detail;
  }

  render()  {
    return(
      <h1>{this.input}</h1>
    );
  }
}

export default ChildComponent;

I currently have this set up because if I do not have a boolean before calling the child component, I will not be able to render it. So, it makes sense that I have to set renderingBool to false (by selecting "--") and then set it to true again by selecting another choice, all in an effort to re-render the childComponent.

Is there a workaround to this? Can I re-render the child component without having to select the default value?

2 Answers2

0

You need to understand that the problem is in ChildComponent, not your App component.

render()  {
    return(
      <h1>{this.input}</h1>
    );
  }

As you can see, you always render this.input. It is supposed to be assigned props.detail, but note that assignment only happens in constructor, which means it's not dynamic enough.

So, change your render method on ChildComponent to this.

...
<h1>{this.props.detail}</h1>
...
Hayden S.
  • 742
  • 4
  • 10
  • hey Hayden, thanks for your response! follow up: is it possible that on every click of an option and the subsequent re-render of the childComponent, I can get the childComponent to fetch a URL and retrieve the data? here is a codesandbox: https://codesandbox.io/s/interesting-fast-79j7n – TrustLearning Aug 13 '20 at 06:24
  • Can you explain more about what you want? – Hayden S. Aug 13 '20 at 06:31
  • Hey Hayden, I actually asked a separate question here: https://stackoverflow.com/questions/63389766/reactjs-how-to-fetch-inside-a-child-component-with-details-passed-on-by-props – TrustLearning Aug 13 '20 at 07:01
0

Issue

Child component isn't reacting to updated props. You only see the updated value after switching the select value back to "--" and the component is remounted.

{renderingBool && ( // <-- when false, unmounts child
  <ChildComponent
    history={this.props.history}
    detail={this.state.value}
  />
)}

class ChildComponent extends Component{
  constructor(props)  {
    super(props);

    this.input = props.detail; // <-- only gets prop value when mounting
  }

  render()  {
    return(
      <h1>{this.input}</h1>
    );
  }
}

Solution

Simply render props in the child

class ChildComponent extends Component{
  render()  {
    return(
      <h1>{this.props.detail}</h1>
    );
  }
}

Suggestion

Set initial value to "--" and disable that option in the UI so it isn't selectable

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      value: "--", // <-- set initial select value
      prevValue: "",
      submitted: false
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    event.preventDefault();
    const { value } = event.target;
    this.setState({
      prevValue: this.state.value,
      submitted: true,
      value
    });
  }

  render() {
    return (
      <div className="Base">
        <h1> By Productline </h1>
        <form>
          <label className="label">
            Select Workflow: {"               "}
            <select value={this.state.value} onChange={this.handleChange}>
              <option disabled value="--"> -- </option> // <-- disable so it can't be chosen
              <option value="test1">test1</option>
              <option value="test2">test2</option>
              <option value="test3">test3</option>
            </select>
          </label>
        </form>

        <div>
          {this.state.value !== "--" && (
            <ChildComponent
              history={this.props.history}
              detail={this.state.value}
            />
          )}
        </div>
      </div>
    );
  }
}

Edit how-to-re-render-a-component-after-another-choice-is-clicked-on-form

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • hey drew, thanks for your response! I have a follow up: is it possible that on every click of an option and the subsequent re-render of the childComponent, that I can get the childComponent to fetch a URL and retrieve the data? I've attached a codesandbox: https://codesandbox.io/s/interesting-fast-79j7n EDIT: the only way I can fetch is when I reset and set the choice to "--" – TrustLearning Aug 13 '20 at 06:23