1

I can not seem to get props working for passing information from my child class up to my parent class. What I am trying to do, is to detect what dropdown menu option someone has chosen, send that information up to the parent class which then takes the chosen option and runs a call to backend that then returns a list of database items which match the chosen option.

Below is the child class:

import React,{useState} from 'react';
import SEPractices from "../dummydata/SEPractices"

  const optionItems = SEPractices.map((SEPractice) =>
                <option key={SEPractice.practice}>{SEPractice.practice}</option>
            );
  const Dropdown = () => {
  const [selectValue, setValue] = useState("")
    
  const handleSelect = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
    this.props.handlePractice(e.target.value);
}

    return (
        <div>
             <select value={selectValue} onChange={handleSelect}> 
                
               <option value="dummyData">
                 Select an SE Practice
                 </option>
                {optionItems}
             </select>
         </div>

    )
  }
  export default Dropdown;

Below is the parent class:

import React,{useState} from "react";
import Styles from "../components/tablestyle.js";
import Table from "../components/evidencetable.js";
import tablecolumns from "../components/tablecolumns.js";
import Dropdown from "../components/Dropdown.js";
import axios from "axios";

//const dbArticles = [];
class SEPractice extends React.Component{
  /*constructor(props){
  this.state = {dbArticles: []};
  this.componentDidMount = this.componentDidMount.bind(this);
  this.getArticles = this.getArticles.bind(this);
  this.practice = this.practice.bind(this);
  }*/
  state={
    dbArticles: []
  }
  
  handlePractice (Option) {
  
    console.log("hi");

    // axios.get(`https://protected-plains-77403.herokuapp.com/api/articles/${Option}`)
    axios.get(`https://localhost:5000/api/articles/${Option}`)
    .then((response) =>{
      const data = response.data;
      this.setState({dbArticles: data});
      console.log('state', this.state);
    })
    .catch(()=>{
      alert('error retrieving data');
    });
  }

  componentDidMount = () =>{
    this.getArticles();
  }
  getArticles = () =>{
    axios.get('https://protected-plains-77403.herokuapp.com/api/articles')
    .then((response) =>{
      const data = response.data;
      this.setState({dbArticles: data});
      console.log('state', this.state);
    })
    .catch(()=>{
      alert('error retrieving data');
    });
  }
/*practice =() =>{
  const [selected, setSelected] = useState('');
  const practiceHandler = (e) =>{
    setSelected(e);
  }
}*/
render() {
    return (

      <div>
        <h2>Select SE Practice to get evidence for the claimed benefits</h2>
            <Dropdown onDropdown={this.handlePractice}/>
            <Styles>
                <Table
                data={this.state.dbArticles}
                columns={tablecolumns}
                />
            </Styles>
      </div>
    );
}
}
export default SEPractice;  

I followed a few articles and stack overflow blogs and they all say to do this.props.method which I did:

  const handleSelect = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
    this.props.handlePractice(e.target.value);
}

3 Answers 3

2

In the parent class, you are not correctly binding the method in the constructor. You need the following:

class SEPractice extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
       dbArticles: []
    }

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

The handlePractice method is now bound to the parent component. When you pass it to the child component, you assign it to the property onDropdown. You need to then access it correctly from the child component using the onDropdown property to which you have assigned it. Note, because the child component is a functional component, we do not use this.props, like you did in the parent component which is a class component. Like so:

  const Dropdown = (props) => { //Notice here we passed props into the function that generates the component
    const [selectValue, setValue] = useState("")
    
    const handleSelect = (e) => {
      console.log(e.target.value);
      setValue(e.target.value);
      props.onDropdown(e.target.value); //Not this.props
    }

    return (
        <div>
             <select value={selectValue} onChange={handleSelect}> 
                
               <option value="dummyData">
                 Select an SE Practice
                 </option>
                {optionItems}
             </select>
         </div>

    )
  }
  export default Dropdown;

}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for this answer, I really appreciate it a lot! When I make the changes, I still get the 'props' is not defined no-undef error in the child class.
When does this error appear? When you attempt to make a selection from the dropdown?
It makes an error on runtime. So as soon as I start the Node.js server it says failed to compile followed by the error.
Oh, my bad, I missed the (props)! It is now working!! Thank you so much.
0

you need to change your code to


const handleSelect = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
    this.props.onDropdown(e.target.value);
}


The reason is because on the dropdown component you named the prop onDropdown

When you are trying to console.log your state after doing setState do it like so

      const data = response.data;
      this.setState({dbArticles: data},() => console.log('state', this.state));
    }) 

the reason is that setState is asynchronous and the second argument is a callback that fires after state has actually been set.

1 Comment

Thank you for that imporovement on the code! It makes a lot of sense. I do still get the 'props' is not defined no-undef error when I changed it to onDropdown.
0

You are not receiving any props in the component as you are not allowing for the parameter and also acting on the incorrect prop name:

const Dropdown = () => { // missing props here
  const [selectValue, setValue] = useState("")
    
  const handleSelect = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
    this.props.handlePractice(e.target.value); // problem here
}

    return (
        <div>
             <select value={selectValue} onChange={handleSelect}> 
                
               <option value="dummyData">
                 Select an SE Practice
                 </option>
                {optionItems}
             </select>
         </div>

    )
  }
  export default Dropdown;

Update to receive the props:

const Dropdown = (props) => {
  const [selectValue, setValue] = useState("")
    
  const handleSelect = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
    props.onDropdown(e.target.value); // note correct name
}

    return (
        <div>
             <select value={selectValue} onChange={handleSelect}> 
                
               <option value="dummyData">
                 Select an SE Practice
                 </option>
                {optionItems}
             </select>
         </div>

    )
  }
  export default Dropdown;

Codesandbox Demo

2 Comments

I made the change but still seem to get the 'props' is not defined no-undef error. Thanks for the comment as well!
See the demo, better to stay with classes or functional components, not mix both imo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.