cbdeveloper
cbdeveloper

Reputation: 31365

Destructuring props dynamically?

I'm currently building an AddProductPage component for my web app. It receives a bunch of props from its parent AddProductContainer and should divide those props among many smaller components that it renders on the page.

Example:

AddProductPage.js

function AddProductPage(props) {

  return(
    <React.Fragment>
      <Component1
        propsA={props.propsA}
        propsB={props.propsB}
      />
      <Component2
        propsC={props.propsC}
        propsD={props.propsD}
        propsE={props.propsE}
      />
      // And so on...
    </React.Fragment>
  );
}

I've decided that I will to divide the full props object into smaller objects, one for each component, so I can see what my code will render on the page in a cleaner look. Like:

function AddProductPage(props) {

  const comp1Props = {
    propsA: props.propsA,
    propsB: props.propsB
  }

  const comp2Props = {
    propsC: props.propsC,
    propsD: props.propsD,
    propsE: props.propsE
  }

  return(
    <React.Fragment>
      <Component1 {...comp1Props}/>    // <--- Easier to see what will render
      <Component2 {...comp2Porps}/>
      // And so on...
    </React.Fragment>
  );
}

I'm currently thinking if is it possible to dynamically destructure (or some other approach) all props into single variables so I can write something like this:

function AddProductPage(props) {

  // Some code to destructure all props into single variables

  const comp1Props = {
    propsA,
    propsB
  };

  const comp2Props = {
    propsC,
    propsD,
    propsE
  };

  return(
    <React.Fragment>
      <Component1 {...comp1Props}/>    // <--- Easier to see what will render
      <Component2 {...comp2Porps}/>
      // And so on...
    </React.Fragment>
  );

}

How can I do this?

EDIT

I think I wasn't being clear enough with my question. But what I meant with dynamically is to destructure everything without knowing the props names or how many props there are. Is it possible?

Like:

const {...props} = {...props}; // This is pseudo code

This way I think my code will be as clean as it can get. Thanks.

Upvotes: 1

Views: 8821

Answers (4)

Fraction
Fraction

Reputation: 12964

You can use:

function AddProductPage({propsA, propsB, propsC, propsD, propsE}) {

Or

const {propsA, propsB, propsC, propsD, propsE} = props

Upvotes: 0

Corbuk
Corbuk

Reputation: 700

I am a bit late to the party, but I would like to make a mention how to make your code readable and thus maintainable. You should separate you code and thus separate your concerns.

Personally I think you are thinking overkill for what you need. For every Component1, Component2, Component3 etc. You will be declaring another constvalue, which depending on how many you have will have a performance impact. More importantly, Have you Component and the props being passed in laid out like below (not inline with the component) makes it a lot cleaner.

class MyComponentName extends Component {
  getComponentOne = () => {
    const { propsA, propsB } = this.props;

    //Any other logic for component 1 can go here.

    return (
      <Component1
        propsA={propsA}
        propsB={propsB}
      />
    );
  };

  getComponentTwo = () => {
    const { propsC, propsD, propsE} = this.props;

    //Any other logic for component 2 can go here.

    return (
      <Component2
        propsC={propsC}
        propsD={propsD}
        propsE={propsE}
      />
    );
  };

  // Other component method getters

  addProductPage = () => (
    <React.Fragment>
      {this.getComponentOne()}
      {this.getComponentTwo()}
      // Get other component methods
    </React.Fragment>
  );

  render() {
    return(
      // Return whatever you wish here.
    );
  }
}

export default MyComponentName;

Two great quotes to think about are from C. Martin in which he stated in his book Clean Code: A Handbook of Agile Software Craftsmanship:

Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to be that way.

AND

“Clean code is code that has been taken care of. Someone has taken the time to keep it simple and orderly. They have paid appropriate attention to details. They have cared.”

Also A note regarding my example above, I am using class components, as I don't know if your component has any other methods/ logic. As if you have other methods in your functional component, on each render those methods would get reinitiated, which again would be a big performance issue.

If you just have a functional component and don't want to separate your code/ has no logic and it only return JSX then you could do it the following way.

const MyComponentName = ({
  propA,
  propB,
  propC,
  propD,
  propE,
  // Rest of props
}) => (
  <React.Fragment>
    <Component1
      propsA={propsA}
      propsB={propsB}
    />
    <Component2
      propsC={propsC}
      propsD={propsD}
      propsE={propsE}
    />
    // Rest of you components (If simply returning JSX)
  </React.Fragment>
);

Hope the above is of some help to you.

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074335

The "Some code to destructure all props into single variables" would be simple destructuring:

const { propsA, propsB, propsC, propsD, propsE } = props;

Live Example:

const props = {
    propsA: "a",
    propsB: "b",
    propsC: "c",
    propsD: "d",
    propsE: "e"
};

const { propsA, propsB, propsC, propsD, propsE } = props;

const comp1Props = {
    propsA,
    propsB
};

const comp2Props = {
    propsC,
    propsD,
    propsE
};

console.log(comp1Props);
console.log(comp2Props);
.as-console-wrapper {
  max-height: 100% !important;
}


In comments you've clarified:

what I meant with dynamically is to destructure everything without knowing the props names or how many props there are.

I asked how you would know what to assign to comp1Props vs comp2Props, and you said:

I woud still decide that and create those objects manually. But if a pass a new prop to AddProductPage, I would like it to be automatically destructured and available to add that into the comp1Props object, for example. Otherwise I would have to remember to destructure it first and then add it to the comp1Props object.

So the question is: Can you automatically create constants/variables for all of props's properties in AddProductPage, so that they're all available to use in the code creating comp1Props and comp2Props?

No, you can't do that without using a confusing feature (with) that isn't available in strict mode (which is enabled by default in modules). If you could use with, you'd just do with (props) { /*...*/ } and create your comp1Props and comp2Props within that block. But you can't use with in modern JavaScript.

You're probably best off doing what you're already doing:

const comp1Props = {
    propsA: props.propsA,
    propsB: props.propsB
};

But if you want to make it shorter, you can give yourself a reusable utility function:

function pick(source, ...props) {
    const result = {};
    for (const prop of props) {
        result[prop] = source[prop];
    }
}

and then use it in AddProductPage:

function AddProductPage(props) {
  const comp1Props = pick(props, "propsA", "propsB");
  const comp2Props = pick(props, "propsC", "propsD", "propsE");

  return(
    <React.Fragment>
      <Component1 {...comp1Props}/>
      <Component2 {...comp2Porps}/>
      // And so on...
    </React.Fragment>
  );
}

(Some would shoehorn that into a reduce call, but there's no need.)

Upvotes: 7

Ashish
Ashish

Reputation: 4330

you can do something like

function AddProductPage(props) {
    //Destructuring props and storing each keys in a sep varaiable  
    const { propsA, propsB, propsC, propsD, propsE } = props;   
    const comp1Props = {
        propsA,
        propsB
    };

    const comp2Props = {
        propsC,
        propsD,
        propsE
    };

    return(
        <React.Fragment>
            <Component1 {...comp1Props}/> 
            <Component2 {...comp2Porps}/>
            // And so on...
      </React.Fragment>
    );

}

Upvotes: 2

Related Questions