How to use constructor value outside constructor?

2019-07-23 06:00发布

问题:

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?

回答1:

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.



回答2:

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