Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make variables available to every method in a component?

Let's say I am mapping my store state to props like so:

const mapStateToProps = state => {
    return {
        somelist: state.somelist
    };
};

And I need to create variables in my render like:

render() {
  const { somelist } = this.props;
  const somenestedlist = somelist.list;
}

However, in my render method I am also calling another method that needs those same variables. So I can either:

(1) Pass it from the render method like:

render() {
  const { somelist } = this.props;
  const somenestedlist = somelist.list;

  <div onClick={()=>this.someothermethod(somenestedlist)}
}

(2) Redeclare them in the someothermethod() which is not DRY.

(3) Create a function that returns the needed value and call it wherever it's needed as in:

getList() {
  const { somelist } = this.props;
  const somenestedlist = somelist.list;

  return somenestedlist;
}

OR is there a better way than any of these examples?

like image 485
catandmouse Avatar asked Sep 10 '18 02:09

catandmouse


3 Answers

You can convert somenestedlist in mapStateToProps:

const mapStateToProps = state => {
    return {
        somelist: state.somelist,
        somenestedlist: state.somelist.list
    };
};

In everywhere, you can use this.props.somenestedlist

like image 59
san Avatar answered Nov 15 '22 21:11

san


If you don't need to alter the list, then this.props.someList is accessible from within any of the class' methods.

However, if you want to add/remove items from this list from within the component without changing someList, then the simplest solution is to declare a nestedList variable from the someList source in the class constructor (the example below, where state = {...}, is syntactic sugar for the same thing), and then utilize React state to alter this new list.

Now, you can either discard the new list or call a Redux action creator to save and update the props list (consequently, you can also reset both lists as long as the initial list source stays constant).

Working example: https://codesandbox.io/s/6w5r5o32qk

import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import { resetList, saveList } from "./listActions";

const newData = [
  {
    _id: "5b9c3b351e5f7d9b827df4ce",
    index: 0,
    guid: "048e6f79-c33c-42fc-83e3-05f5b467240d",
    isActive: false,
    balance: "$1,663.79",
    picture: "http://placehold.it/32x32",
    age: 23,
    name: "Tonya Drake"
  },
  {
    _id: "5b9c3b350e7b14d4c94043f2",
    index: 1,
    guid: "1e3daeeb-36fd-4e52-a30e-5dbaedec8438",
    isActive: true,
    balance: "$2,263.69",
    picture: "http://placehold.it/32x32",
    age: 40,
    name: "Patricia Phelps"
  }
];

class Example extends Component {
  state = {
    addButtonClicked: false,
    saveButtonClicked: false,
    nestedList: this.props.someList
  };

  componentDidUpdate = prevProps => {
    if (prevProps.someList !== this.props.someList) {
      this.setState({
        nestedList: this.props.someList
      });
    }
  };

  addData = () => {
    this.setState(prevState => ({
      addButtonClicked: true,
      nestedList: [...this.state.nestedList, newData]
    }));
  };

  resetData = () => {
    this.setState(prevState => {
      this.props.resetList();
      return {
        addButtonClicked: false,
        saveButtonClicked: false,
        nestedList: this.props.someList
      };
    });
  };

  saveNewList = () =>
    this.setState(prevState => {
      this.props.saveList(this.state.nestedList);
      return { saveButtonClicked: true };
    });

  render = () => (
    <div style={{ textAlign: "center" }}>
      <h1>Utilizing React State</h1>
      <button
        className="uk-button uk-button-primary uk-button-large"
        type="button"
        onClick={this.addData}
        disabled={this.state.addButtonClicked || this.state.saveButtonClicked}
        style={{ marginRight: 20 }}
      >
        Add Data
      </button>
      <button
        type="button"
        className="uk-button uk-button-danger uk-button-large"
        onClick={this.resetData}
        disabled={!this.state.addButtonClicked && !this.state.saveButtonClicked}
        style={{ marginRight: 20 }}
      >
        Reset List
      </button>
      <button
        type="button"
        className="uk-button uk-button-secondary uk-button-large"
        onClick={this.saveNewList}
        disabled={
          (this.state.addButtonClicked && this.state.saveButtonClicked) ||
          (!this.state.addButtonClicked && !this.state.saveButtonClicked)
        }
      >
        Save List
      </button>
      <pre style={{ height: 600, overflowY: "auto", textAlign: "left" }}>
        State List&nbsp;
        <code>{JSON.stringify(this.state.nestedList, null, "\t")}</code>
        <br />
        <br />
        Props List&nbsp;
        <code>{JSON.stringify(this.props.someList, null, "\t")}</code>
      </pre>
    </div>
  );
}

export default connect(
  state => ({ someList: state.list }),
  { resetList, saveList }
)(Example);
like image 24
Matt Carlotta Avatar answered Nov 15 '22 22:11

Matt Carlotta


If you don't want to redeclare variables in every function you use, then... I think your only option is to use the value directly from the props...

Then, do this:

yourMethod(){
    //Do somethign with data directly, no need to declare a const again
    this.anotherMethod(this.props.somelist.list);
}

instead of:

const { somelist } = this.props;
const somenestedlist = somelist.list;

I mean, the values ARE already available to all methods, just use them... const { somelist } = this.props; is only used as a helper to not write this.props.somelist all over the method.

like image 24
Pipe Avatar answered Nov 15 '22 20:11

Pipe