2

In React JS, I am having trouble passing a value from a child component up to the parent component

this question is a follow-up to previous question In React JS, how do I tell a parent component that something has happened in the child?

here is the code example I am working with...

I have one problems and two questions:

1) although 'label' is in scope (and I can see it has a value in the debugger) in the render method of InfoBox, when it gets passed up to ContainingBox's boxChosen method, it always comes up 'undefined'. what am I doing wrong here?

2) Is there any way to reduce the repetition (DRY this up) when using JSX to construct the InfoBox. In particular, it bothers me that selectBox={this.boxChosen} is repeated for each instance of InfoBox in the JSX

3) is there any common pattern or accepted practice for the naming of the methods in children or parents? In particular, you'll see that this code lets me define one method called selectBox in the child and another one called boxChosen in the parent. This seems arbitrary to me, as I just picked two separate names that didn't collide so as to make it more understandable. But it strikes me as in a larger app you'd want a consistent function naming pattern to identify which methods were 'pass through' methods (in this case, selectBox) simply passing stuff back up to parents. I don't know; just a thought about whether or not there's a naming convention.

import React from 'react';

import styled from 'styled-components'
import './App.css';


const StyledInfoBox = styled.div`
  width: 100px;
  border: solid 1px green;
  padding: 10px;
  cursor: pointer;
`


class InfoBox extends React.Component {
  constructor({blurb}) {
    super()
    this.state = {
      label: (blurb ?  blurb.label : ""),
    }
  }

  render() {
    const {label} = this.state
    return (
      <StyledInfoBox onClick={() => {
        const {label} = this.state

        // although 'label' is in scope here, it seems to not be
        // correctly passed up to selectBox
        this.props.selectBox(this.label)
      }
      } >
        {label}
      </StyledInfoBox>
    )
  }
}

class ContainingBox extends React.Component {

  boxChosen =(label) => {

    // for some reason label comes out as undefined here
    console.log("boxChosen.......", label)

  }


  render() {
    return (
      <div>
        <InfoBox key={1} blurb={{label: "Aenean malesuada lorem"}} selectBox={this.boxChosen}  />
        <InfoBox key={2} blurb={{label: "Lorem Ipsum dor ameet"}} selectBox={this.boxChosen} />
      </div>
    )
  }
}

function App() {
  return (
    <div className="App">
      <ContainingBox />
    </div>
  )
}

export default App;
halfer
  • 19,824
  • 17
  • 99
  • 186
Jason FB
  • 4,752
  • 3
  • 38
  • 69
  • Possible duplicate of [How to pass data from child component to its parent in ReactJS?](https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs) – ekuusela Oct 18 '19 at 18:22

1 Answers1

2
  1. this.label doesn't exist, so it's undefined. Either pass this.state.label, or since youre destructuring the object, just label. Just a minor mistake
 render() {
    const {label} = this.state
    return (
      <StyledInfoBox onClick={() => {this.props.selectBox(label)}}>
        {label}
      </StyledInfoBox>
    )
  }

You don't need to do the destructuring twice either.

2. No, you have to pass all the props to each component. No reason you couldn't throw the boxes in a loop though. You can put the labels in an array and iteratively pass everything. Now you only have to actually write it one time.

class ContainingBox extends React.Component {
  const boxChosen =(label) => {}

  const labels = ['Aenean malesuada lorem', 'Lorem Ipsum dor ameet'];

  render() {
    return (
      <div>
        {labels.map((ele, index) => {
           <InfoBox
             key={index}
             blurb={{label: ele}}
             selectBox={this.boxChosen}
           />
        })}
      </div>
    )
  }
}
  1. Someone else can probably answer this one better than I can. There isn't a true convention besides name them something that makes sense. You're right that you can name them different things, because they're just functions in different scopes. There's nothing special about them. You can name them the same thing, but you don't need to. The best thing you can do is name them something that is "self documenting" where it is being defined.
Jtcruthers
  • 854
  • 1
  • 6
  • 23
  • that's it. when I changed `this.props.selectBox(this.label)` to `this.props.selectBox(label)` it worked. And yes thanks for pointing out the double destructing too, I was just fiddling around but I see now that `label` is already in scope there because of the fat arrow after onClick – Jason FB Oct 18 '19 at 18:32
  • @JasonFB I answered your second question as well – Jtcruthers Oct 18 '19 at 18:35
  • 1
    re #2 - yes, makes sense. your example does meet the test of DRY, as it reduces repetition and probably I will want the data in an array anyway as I work my way up the application. re #3 -- yes I think I understand, at this point it is a matter of the dev taking responsibility for the naming. – Jason FB Oct 18 '19 at 18:47
  • Exactly. You dont want to force the same name too hard, because you should be able to reuse the component in other places. So don't try to couple it too hard – Jtcruthers Oct 18 '19 at 18:53