Skip to content

[Documentation] Re-add "Transferring with ... in JSX" to "JSX In-Depth / Spread Attributes" #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 13, 2017

Conversation

hellobrian
Copy link
Contributor

resolves #109

Re-add Transferring with ... in JSX docs previously published with React v15-ish.

The overall content has been kept the same but I slightly changed the example to better reflect why using ...other can be useful (I also wanted to avoid an example that uses a <div> as a checkbox).

In the example, I show a PrimaryButton component that can receive an unknown onClick prop function. Things like buttons handle a lot of different events -- instead of passing every possible synthetic event down as a prop, making use of ...other helps to keep the code for PrimaryButton from getting bloated.

If it helps, I've also made the example live on code sandbox but didn't include it...I wasn't sure if it was totally needed, and since the docs surface codepen examples exclusively. I don't know if you all want to stay consistent with one example platform.

Edit React: Transferring with ... in JSX

re-add Transferring with ... in JSX docs previously published with React v15-ish
@facebook-github-bot
Copy link
Collaborator

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

@hellobrian hellobrian changed the title docs/update-jsx-in-depth/spread-attrs docs: re-add "Transferring with ... in JSX" to JSX In-Depth / Spread Attributes Oct 10, 2017
@hellobrian hellobrian changed the title docs: re-add "Transferring with ... in JSX" to JSX In-Depth / Spread Attributes [Documentation] Re-add "Transferring with ... in JSX" to "JSX In-Depth / Spread Attributes" Oct 10, 2017
@facebook-github-bot
Copy link
Collaborator

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@reactjs-bot
Copy link

reactjs-bot commented Oct 10, 2017

Deploy preview ready!

Built with commit 39ef13f

https://deploy-preview-121--reactjs.netlify.com

Copy link
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I slightly prefer the original presentation. It quickly explained what spread props were before going into why they might be problematic. Thoughts?

}
This ensures that you pass down all the props *except* the ones you're consuming yourself.

```js{7}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line number (7) no longer points to the thing I think you want to highlight. I believe you want line 6 (where the other props are actually passed to <button>)>

const PrimaryButton = props => {
const { type, children, ...other } = props;
return (
<button type={type} {...other}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we pick a different example? Since in this case type would be passed the same regardless of whether you plucked it out of props or passed it via other.


This ensures that you pass down all the props *except* the ones you're consuming yourself.

```js{6}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know what this markdown syntax was before, changed it to highlight line 6 like you suggested.

const handleClick = () => console.log("handleClick");

const PrimaryButton = props => {
const { children, ...other } = props;
Copy link
Contributor Author

@hellobrian hellobrian Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we pick a different example? Since in this case type would be passed the same regardless of whether you plucked it out of props or passed it via other. - @bvaughn

To your original comment, I updated the example removing type from this line. I wasn't trying to focus on type but I was trying to show how PrimaryButton could now receive unknown props like onClick

<PrimaryButton type="button" onClick={handleClick}>

If this still isn't preferrable, I can just use the original example as-is from the original docs (Transferring with ... in JSX)

Copy link
Contributor

@bvaughn bvaughn Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is better! But it's still a little awkward since you could also pass children via the spread operator as well- and <button type="button"> isn't a valid attribute. These might be confusing to readers. (They might get distracted thinking, "why is that..." instead of focusing on the spread operator.)

How do you feel about something like this?

const handleClick = () => console.log("handleClick");

const PrimaryButton = props => {
  const { type, ...other } = props;
  const className = type === "primary" ? "PrimaryButton" : "SecondaryButton";
  return <button className={className} {...other} />;
};

const App = () => {
  return (
    <div>
      <PrimaryButton type="primary" onClick={handleClick}>
        Hello World!
      </PrimaryButton>
    </div>
  );
};

Copy link
Contributor Author

@hellobrian hellobrian Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works too, but <button type="button"> is a valid attribute (see MDN). Even though the validity of the attribute is important, I agree, it could be confusing for readers either way. Instead, we can strip down this example even further so that it shows all the props coming from ...other

const handleClick = () => console.log("handleClick");

const PrimaryButton = props => {
  const { ...other } = props;
  return <button {...other} />;
};

const App = () => {
  return (
    <div>
      <PrimaryButton onClick={handleClick}>
        Hello World!
      </PrimaryButton>
    </div>
  );
};

☝️ How about this? Also, thanks for taking a look at this!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<button type="button"> is a valid attribute

You are correct, of course. Sometimes I forget how wonky HTML attributes are 😆

const { ...other } = props;
return <button {...other} />;

I think this maybe leaves too much to the imagination. "Why would I do this? What's the point?" I think we should show at least one prop being plucked out.

Copy link
Contributor Author

@hellobrian hellobrian Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆Alright, with everything said so far,

I can pluck className instead of type to avoid confusion
(hopefully, I'm using the "pluck" terminology correctly)

The PrimaryButton component takes a className prop. It also takes any number of unknown props through the ...other object, just as long as they are valid HTML attributes for <button>.

const handleClick = () => console.log("handleClick");

const PrimaryButton = props => {
  const { className, ...other } = props;
  return <button className={className} {...other} />;
};

const App = () => {
  return (
    <div>
      <PrimaryButton className="primaryButton" onClick={handleClick}>
        Hello World!
      </PrimaryButton>
    </div>
  );
};

Now, the App component can return the PrimaryButton so that it can receive it's known props (className) and any unknown props through ...other, which contains the following when used in App:

// Contained in { ...other }
{ 
  onClick: handleClick(), 
  children: 'Hello World!' 
}

Copy link
Contributor

@bvaughn bvaughn Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have the same concern as I mentioned before:

// This...
const PrimaryButton = props => {
  const { className, ...other } = props;
  return <button className={className} {...other} />;
};

// Is the same thing as this...
const PrimaryButton = props => {
  return <button {...props} />;
};

I think we should pick a prop out that we don't want to pass on to reinforce the idea of why you might want to pluck things out. It's true that you will sometimes filter a prop out and still pass it through but I think that's not the main point of demonstrating the technique in this section of the docs.

```js{2}
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
Copy link
Contributor Author

@hellobrian hellobrian Oct 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In response to: #121 (comment) (comment thread was getting long)

Thanks for your patience, I think I finally understand what you've been trying to say 😭
My motivation for re-adding this documentation was to surface how you can pass unknown props via spread attributes. But, I can see now that there are more considerations that need to be made when opting to use this syntax, which is what you were trying to communicate.

Thanks again for being so thorough with this PR, @bvaughn

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem at all 😄 It's easy to miscommunicate on a PR.

@@ -245,7 +245,31 @@ function App2() {
}
```

Spread attributes can be useful when you are building generic containers. However, they can also make your code messy by making it easy to pass a lot of irrelevant props to components that don't care about them. We recommend that you use this syntax sparingly.
You can also pick specific props that your component will consume while passing all other props using the spread operator.
This ensures that the component consumes the `kind` prop only, and passes down all other props via `...other`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this sentence may not be necessary. I think it might be nice to just show the example and then explain it below (like you already do) 👍

};
```

In the example above, the `kind` prop is safely consumed and *is not* passed directly to the `<button>` element in the DOM.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion / nit:

In the example above, the kind prop is safely consumed and is not passed on to the <button> element in the DOM.

In the example above, the `kind` prop is safely consumed and *is not* passed directly to the `<button>` element in the DOM.
All other props are passed via the `...other` object making this component really flexible. You can see that it passes an `onClick` and `children` props.

Spread attributes can be useful but not to pass invalid HTML attributes to the DOM. They can also make your code messy by making it easy to pass a lot of irrelevant props to components that don't care about them. We recommend using this syntax sparingly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:

Spread attributes can be useful but they also make it easy to pass unnecessary props to components that don't care about them or to pass invalid HTML attributes to the DOM. We recommend using this syntax sparingly.

Copy link
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for iterating on this with me 👍

@bvaughn bvaughn merged commit 2f04c4f into reactjs:master Oct 13, 2017
@hellobrian hellobrian deleted the patch-1 branch October 13, 2017 18:23
jhonmike pushed a commit to jhonmike/reactjs.org that referenced this pull request Jul 1, 2020
BetterZxx pushed a commit to BetterZxx/react.dev that referenced this pull request Mar 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing docs about Transferring Props in JSX
4 participants