1

I'am working Reactjs Weather project. I'am getting the value in one of the method in Child Component (Form.js) after submitting and I need to get that value in Parent Component (App.js). How to get that value?

  1. App.js file (Parent Component)
getWeather = async (e) => {
    e.preventDefault();

}
  1. Form.js file (Child Component)
import React, { Component } from 'react'
import Background from '../video/rain_drop2.jpg';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

import { MDBContainer,
    MDBRow,
    MDBCol,
    MDBCard,
    MDBCardBody,
    MDBCardHeader,
    MDBBtn,
    MDBInput } from 'mdbreact'


const sectionStyle = {
    backgroundImage: `url(${Background})`,
    opacity: '0.92',
    width: '90%',
    backgroundSize: 'cover',
    backgroundPosition: 'center',
    height:'99%',
    position:'absolute',
    filter:'blur(1.8px)'
    };

class Form extends React.Component {
  constructor(props){
    super(props);

    this.state = {
      fields: {},
      errors: {}
    }
  }

  handleValidation(){
    let fields = this.state.fields;
    let errors = {};
    let formIsValid = true;

    //Name
    if(!fields["city"]){
      formIsValid = false;
      errors["city"] = "Cannot be empty";
    }

    this.setState({errors: errors});
    return formIsValid;
  }

  submitDetails = (e) => {
    e.preventDefault();

    // I want this value to be accessed in App.js file
    const city = e.target.city.value
    console.log('VALUE', city)

    browserHistory.push()
    if(this.handleValidation()){
      toast("Form Submitted!.")
    }else{
      toast("Form has errors.")
    }

  }

  handleChange(field, e){           
    let fields = this.state.fields;
    fields[field] = e.target.value;        
    this.setState({fields});
  }

  render(){
    return (

      <div>  
<MDBContainer>
<MDBRow>
  <MDBCol>
  <MDBCard  style={sectionStyle}></MDBCard>
  <MDBCard className="card" style={{zIndex:'1', background: 'none'}}>
  <MDBCardBody >
    <MDBCardHeader style={{background: '#ecf0f1', opacity:'0.7', borderRadius: '10px',
    fontFamily: 'Josefin Sans'}}>
      <h3 className="my-3 text-center" style={{color: '#535c68'}}>
         Weather Finder
      </h3>
    </MDBCardHeader>
    <br/>
    <form onSubmit= {this.submitDetails.bind(this)}>
      <div className="blue-grey-text">
      <span className="error">{this.state.errors["name"]}</span>
        <MDBInput
          ref="city"
          label="City"
          icon="city"
          type="text"
          name="city"
          id="text-input"
          onChange={this.handleChange.bind(this, "city")}
          value={this.state.fields["city"]}
        />
        <span style={{color: "red"}}>{this.state.errors["city"]}</span>

        </div>
        <br/>

      <div className="text-center mt-4">
        <MDBBtn
          color="blue-grey"
          className="mb-3"
          type="submit"
          value="Submit"
        >
          Search Weather
        </MDBBtn>
        <ToastContainer />
      </div>
      </form>
    </MDBCardBody>
    </MDBCard>
    </MDBCol>
  </MDBRow>
  </MDBContainer>
  </div>
    )
  }
}

export default Form;

Any suggestions highly appreciated... Thanks in advance

Jee Mok
  • 6,157
  • 8
  • 47
  • 80
Pranav
  • 1,487
  • 2
  • 25
  • 53

3 Answers3

0

When rendering the child component in parent component, pass a function, defined in parent component, to the child component as a prop.

When you get the required value in child component, call the function that was passed from parent component as a prop and pass the value to that function as an argument.

Parent Component

// function to be called from child component
foo = (value) => {
   // code
};

render() {
   return (
      <ChildComponent foo={this.foo}/>
   );
}

Child Component

bar = () => {
   const value = // get the value
   // call the foo function of parent component and pass the value
   this.props.foo(value);
};
Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • Thanks for the reply... Both of my components are classes... So, does the logic remains same or need to change? – Pranav Oct 28 '19 at 11:29
0

Most common method for this is to use callback:

  • in child form component you define new prop 'onSubmit'
  • in parent App component you define 'submitHandler' function with 'data' parameter:

handleSubmit = data => {/* your logic here */}
render => (<Form onSubmit={this.submitHandler}/>)
  • And last step in child component's method 'submitDetails' you call this.props.onSubmit(data);
layonez
  • 1,746
  • 1
  • 16
  • 20
0

You can just provide callback from parent component for that:

const Parent = () => {
  const [ weather, setWeather ] = useState(null);

  return (
    <Child setWeather={ setWeather } />
  );
};

const Child = ({ setWeather }) => {
  const getWeather = () => { ... };
  const onClick = () => {
    const weather = getWeather();
    setWeather(weather);
  };

  return (
    <button onClick={ onClick }>Get Weather</button>
  );
}
Andres
  • 967
  • 6
  • 7
  • Thanks for the reply... Here Both of my components are classes... So, what changes do I've to make? – Pranav Oct 28 '19 at 11:33