1

In my component I'm receiving an array object(3 objects only). I want to display them separately and also want to add a onClick event to them so that when user clicks any of them I can render different component for each case.
Now the problem is I am accessing the variables inside constructor and rest of the component is outside that scope. What to do in this situation??

import React, { Component } from 'react';
import '../App.css';
import {withRouter} from 'react-router';
import MonthToDate from './monthtodate';
import QuarterToDate from './quartertodate';
import YearToDate from './yeartodate';
class Dashboard extends Component {

  constructor(props){
    super(props);
    if(this.props.location && this.props.location.state){
      console.log(this.props.location.state.values.o1)
      var o1=this.props.location.state.values.o1;
      var o2=this.props.location.state.values.o2;
      var o3=this.props.location.state.values.o3;
    }
  }
  callMonth = () => { this.props.history.push({pathname: '/monthtodate'}) };
  callQuarter = () => { this.props.history.push({pathname: '/quartertodate'}) };
  callYear = () => { this.props.history.push({pathname: '/yeartodate'}) };

  render() {
    return (
      <div>
        <div onClick:{this.callMonth}>
          <p>MonthToDate: {o1}</p>
        </div>
        <div onClick:{this.callQuarter}>
          <p>QuarterToDate: {o2}</p>
        </div>
        <div onClick:{this.callYear}>
          <p>YearToDate: {o3}</p>
        </div>
      </div>
    );
  }
}

export default Dashboard;          

NOTE: Doing {this.props.location.state.values.o1} doesn't work inside return as it requires that if condition idk why. After much Googling I came to know that there is no class variable in react. Instead it has Context but it's official docs say It is an experimental API and it is likely to break in future releases of React.

The above component is called by Login component ie login.js which is as below:

import React, { Component } from 'react';
import '../App.css';
import Dashboard from './dashboard';
import {withRouter} from 'react-router';
var axios = require('axios');

class Login extends Component {
  constructor(props){
    super(props);
    //this.state = {isToggleOn: true};
    this.loadDashboard = this.loadDashboard.bind(this);
    this.handleOnSubmit = this.handleOnSubmit.bind(this);
    this.setData = this.setData.bind(this);
    this.state = {values:null}
  }
  setData(data){
    this.setState({values:data});
    //console.log(data);
    this.props.history.push({
      pathname: '/dashboard',
      state: { values: data }
  })
  }
  loadDashboard(token){
    console.log(token);
    axios({
      method:'get',
      url:'http://localhost:3000/api/dashboard',
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
     .then( (response) => {
      // console.log(response.data);
      //  this.props.history.push('/dashboard',this.state.values);
       this.setData(response.data);
     })
     .catch(function (error) {
       console.log("Error in loading Dashboard "+error);
     });
  }

  handleOnSubmit = () => {
     //console.log("submittwed");
     axios({
       method:'post',
       url:'http://localhost:3000/authenticate',
       data: {
         email: 'test@mail.com',
         password: 'apple'
       },
     })
      .then((response) => {
        var token = response.data.auth_token;
      //  console.log(token);
        this.loadDashboard(token);
      })
      .catch(function (error) {
        console.log("Error in login "+error);
      });
   }

  render() {
    return (
      <div>
         Username: <input type="email" name="fname" /><br />
         Password: <input type="password" name="lname" /><br />
         <button onClick={this.handleOnSubmit}>LOG IN</button>     
      </div>
    );
  }
}

export default Login;       
  • How do I pass the variable throughout this class. (NOTE: I don't want to change it in future, just want to display it so no REDUX pls).
  • Is there any better approach to tackle this problem?
noobie
  • 751
  • 4
  • 13
  • 33
  • 1
    You should assign the values from props outside the constructor in componentDidMount or componentWillMount to either state or a class variable or better as @Knut said to use it directly in render with a condition that you have used in constructor – Shubham Khatri Sep 12 '17 at 10:32

2 Answers2

2

You can use local component state as below:

constructor(props){
    super(props);
    if(this.props.location && this.props.location.state){
      this.state = {
        o1 : this.props.location.state.values.o1,
        o2 : this.props.location.state.values.o2,
        o3 : this.props.location.state.values.o3
      }
    }
  }

Then use it in your render or whatever method you need as below:

render() {
    return (
      <div>
        <div onClick={()=>{this.callMonth()}}>
          <p>MonthToDate: {this.state.o1}</p>
        </div>
        <div onClick={()=>{this.callQuarter()}}>
          <p>QuarterToDate: {this.state.o2}</p>
        </div>
        <div onClick={()=>{this.callYear()}}>
          <p>YearToDate: {this.state.o3}</p>
        </div>
      </div>
    );
  }

Hope this helps.

tariq
  • 2,193
  • 15
  • 26
  • It is giving me this error: `Error in loading Dashboard Invariant Violation: Objects are not valid as a React child (found: object with keys {invoiceAmt, title}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `Dashboard`.` – noobie Sep 12 '17 at 10:07
  • Can you please place a debugger as first statement in if block in the contructor and then hover the cursor over 'this.props.location.state.values.o1' and confirm what you find there. @mwCoder – tariq Sep 12 '17 at 10:20
  • The value is getting passed to the if statement I have checked. When I log the output it displays the object. Previously I had [this](https://stackoverflow.com/questions/46168684/navigate-to-another-route-on-button-click-and-pass-props-to-it?noredirect=1#comment79304763_46168684) issue due to which I had to implement that if block. – noobie Sep 12 '17 at 10:29
  • So what do you mean when you say I want to display the object, of course you cannot straight away render an object inside render. – tariq Sep 12 '17 at 10:31
  • how you want to display the objects? – tariq Sep 12 '17 at 10:32
  • Your second last comment helped me to understand the issue with object. Now I'm getting this error `Unexpected token in
    `. Why doesn't it recognizes `this.callMonth` (I did defined it)??
    – noobie Sep 12 '17 at 10:38
  • Check my updated answer. Notice how I call this method now – tariq Sep 12 '17 at 10:42
  • Thanks for your time & answer. So `onClick` cannot directly call a function?? – noobie Sep 12 '17 at 11:07
  • onClick can directly call a function, and that is what it is doing. I have passed an arrow function to the onClick property ()=>{ //this is function body} <------- inside this I just called your callMonth. So no magic there. – tariq Sep 18 '17 at 05:52
  • you can also do this onClick={ this.callMonth.bind(this) }, now here you are directly assigning your callMonth method. Also note in that case you have to bind the context of 'this'. – tariq Sep 18 '17 at 05:55
1

You should use the this key word in order to store objects in your class.
so you can do something like this for example:

constructor(props){
    super(props);
    if(this.props.location && this.props.location.state){
      console.log(this.props.location.state.values.o1)
      this.o1=this.props.location.state.values.o1;
      this.o2=this.props.location.state.values.o2;
      this.o3=this.props.location.state.values.o3;
    }
  }

And acces it the same way:

<div onClick:{this.callMonth}>
   <p>MonthToDate: {this.o1}</p>
</div>

That being said, i think you should reconsider this approach and maybe access these values directly from props, or create a state and store them there.
Either way you should update the objects in the componentWillReceiveProps life cycle method

Sagiv b.g
  • 30,379
  • 9
  • 68
  • 99
  • It gives me this error `Objects are not valid as a React child (found: object with keys {invoiceAmt, title}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `Dashboard`.` – noobie Sep 12 '17 at 10:10