Skip to content

Conversation

@lacker
Copy link
Contributor

@lacker lacker commented Oct 5, 2016

This creates two new documents. "JSX In Depth" attempts to describe all of JSX, covering the occasionally-relevant edge cases and weird bits. It should be a document you can go to, to get your weird JSX questions answered. "React Without JSX" just explains how to use React without JSX.

Some docs in the old site are now obsoleted. "JSX Spread Attributes" and "JSX Gotchas" along with a number of the JSX-specific tips are just part of "JSX In Depth" now.

I just removed the translations of the no-longer-there docs. Dunno what else to do with them.

Thanks @spicyj for answering a zillion of my JSX questions in person this afternoon ;-) But still I'm sure I am mis-explaining some things here, so I'd appreciate a sharp-eyed review of this content.

@lacker
Copy link
Contributor Author

lacker commented Oct 5, 2016

screencapture-localhost-4000-react-docs-react-without-jsx-html-1475641564288 1

@lacker
Copy link
Contributor Author

lacker commented Oct 5, 2016

screencapture-localhost-4000-react-docs-jsx-in-depth-html-1475641546630 1

transpiles into:

```js
React.createElement('div', {id: 'blorp'}, null)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor not: you'd almost never want to use the id attribute in React components. Maybe className?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


## HTML Tags and React Components

The first part of a JSX tag determines the type of the JSX element.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"Of the React element"? We don't really say "JSX element" elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm ok I stopped saying "JSX element".

Copy link
Collaborator

Choose a reason for hiding this comment

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

Now that I read @spicyj comments I think it's fine (haha sorry). Since this is a doc about JSX specifically I think it's fine to say JSX Element.

return <MyComponent />;
}
```

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add here:

"If you don't use a JavaScript bundler and added React as a script tag, it is already in scope as a React global."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

```js
import React from 'react';
import Settings from './settings';

Copy link
Collaborator

Choose a reason for hiding this comment

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

I feel like this is a minefield because it only works if you use default exports in that file. Maybe shift the attention from imports to demonstrating this in one file? So that we don't have to explain how modules work in this document.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In general, "dot notation" for components is not popular and I think could live somewhere in the bottom of the document. We don't need to emphasize this, and other topics (such as how expressions and whitespace work) seem more valuable to me.

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 ditched the import and cut it down to one example instead of two to de-emphasize it. I'd like to keep this here though because this section of the document is explaining "all the ways to specify the element type".

import Settings from './settings';

export default function() {
return <Settings.DatePicker barColor={'blue'} />;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's give names to all functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK


export default function() {
// This code attempts to create an HTML <hello> tag and fails
return <hello {toWhat='World'} />
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unintentional braces

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

return <findComponent() />;
}

var MyComponent = findComponent();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move this inside the function? That would be equivalent to your first example then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:

```js
<MyComponent message="&lt;3" />
Copy link
Collaborator

Choose a reason for hiding this comment

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

Today I learned


A React component can't return multiple JSX elements, but a single JSX element can have multiple children, so if you want a component to render multiple things you can wrap it in a `div` like this.

When you pass JSX as the children, `props.children` does not actually let you access the child component from the parent. Instead, it lets you access the return value of `React.createElement` calls using the `React.Children` helper library. Generally, accessing children in this way is only useful to return in a render function, rather than modifying or altering the children.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand this paragraph, can you rephrase (maybe with an example)

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'm just going to delete it - it probably belongs more appropriately in somewhere that discusses "components vs instances vs elements" rather than "all about jsx" because it's not really jsx-specific


<div>{false}</div>

<div>{null}</div>
Copy link
Collaborator

Choose a reason for hiding this comment

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

This document should also include detailed information on how whitespace woks in JSX.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK I added a section about whitespace

@sophiebits
Copy link
Collaborator

No tinyurl please -- no need to add another dependency.

var todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map(renderItem)}
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is an array, each child should have a unique key prop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Collaborator

Choose a reason for hiding this comment

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

An inquisitive reader would think: when don't want to do this instead of using <Item>?

In general we want to encourage people to create components rather than call functions directly. But I guess this is fine.

I don't have a good solution to this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe if we put map body inline as an arrow it is clearer that this pattern is mostly useful for one-liners.

function ListOfTenThings() {
return (
<Repeat>
{(index) => <div>This is item {index} in the list</div>}
Copy link
Contributor

Choose a reason for hiding this comment

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

<Repeat numTimes={10}>? :) Also missing key here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

if (props.number % 2 == 0) {
word = 'even';
} else {
word = 'odd';
Copy link
Contributor

Choose a reason for hiding this comment

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

did you mean description = 'odd'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Fundamentally, JSX just provides syntactic sugar for the `React.createElement(component, props, children)` function. The JSX code:

```js
<MyComponent prop1={'one'} prop2={'two'}>stuff</MyComponent>
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's a little weird to me that this uses {} since people don't ever do that in practice.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That, and let's use double quotes in JSX too since most popular styleguides do that. So it'll be prop1="one".

I would also like us to use more real-world over contrived examples. Like Button or Avatar instead of MyComponent or Foo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

}
```

If the element type starts with a lowercase letter, React will try to create a React element that maps directly to an HTML tag, rather than creating an element based on a custom component. In general, name your components starting with capital letters, and this will be fine. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we do something closer to:

When an element type starts with a lowercase letter, it refers to a built-in component like <div> or <span> and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like <Foo /> compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.

We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.

I don't want to over-pivot on HTML/DOM in the JSX docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK I just took this wording exactly

}
```

You cannot use a general expression as the React element type. If you do want to use a general expression to indicate the type of the element, just assign it to a capitalized variable first. For example, if you have a `findComponent()` function that returns a component, and you want to render one:
Copy link
Collaborator

Choose a reason for hiding this comment

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

A more realistic example here would be

const storyComponents = {
  photo: <PhotoStory />,
  video: <VideoStory />,
};

<storyComponents[this.props.storyType] />

This is where I most frequently see people actually having problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK I switched to use an example like this

function NumberDescriber(props) {
var description;
if (props.number % 2 == 0) {
description = 'even';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use an example where the branches each make a component? Maybe just <strong>even</strong>.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

<MyTextBox autocomplete={true} />
```

In general, we don't recommend using this. It's more consistent to just use the second form and explicitly pass `true`. This behavior is just there so that it matches the behavior of HTML.
Copy link
Collaborator

Choose a reason for hiding this comment

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

In general, we don't recommend using this form because it can be confused with the ES6 object shorthand {autocomplete} which is short for {autocomplete: autocomplete} rather than {autocomplete: true}.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK


This usage is not common, but it works if you want to stretch what JSX is capable of.

`false` or `null` are valid children. They simply don't render. These JSX expressions will all render to the same thing:
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be helpful to explain why this is useful <div>{showHeader && <Header />}<Content /></div>.

P.S. true also is ignored. This is not JSX but is React DOM and might not belong here.

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 like your example. Added

Hmm, this seems like a super logical place to mention that true is ignored... I'll just mention it here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I meant all of true/false/null being ignored is a React DOM thing, not a JSX thing.

can also be written without JSX:

```js
class Hello extends React.Component {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know you show it right below, but can we do const e = in every example except when we're specifically discussing what JSX compiles to? It's the recommended way to use createElement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code block is the only place we use React.createElement and I'd like to have it in one place so it's clear that it doesn't compile to the 'e' thing. How about I make this part specifically say, you can compile out the JSX

}
}

ReactDOM.render(<Hello toWhat={'World'} />,
Copy link
Collaborator

@sophiebits sophiebits Oct 5, 2016

Choose a reason for hiding this comment

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

fb style, please

ReactDOM.render(
  <Hello ... />,
  document...
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

}
}

ReactDOM.render(React.createElement(Hello, {toWhat: 'World'}, null),
Copy link
Collaborator

Choose a reason for hiding this comment

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

ditto

Copy link
Collaborator

Choose a reason for hiding this comment

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

fb indentation

<head>
<meta charset="UTF-8" />
<title>Hello React World!</title>
<title>hello</title>
Copy link
Collaborator

Choose a reason for hiding this comment

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

intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is intentional because downloading the file from your browser will default to naming it the title of the page, and if there's spaces and a ! in it, it's annoying to open it in CLI editors. At least that's how I felt when actually using it to try out some examples.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh. Can we just put a download attribute on the link to this file instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

permalink: docs/jsx-in-depth.html
---

Fundamentally, JSX just provides syntactic sugar for the `React.createElement(component, props, children)` function. The JSX code:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can make this ...children? It accepts variadic arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

Fundamentally, JSX just provides syntactic sugar for the `React.createElement(component, props, children)` function. The JSX code:

```js
<MyComponent prop1={'one'} prop2={'two'}>stuff</MyComponent>
Copy link
Collaborator

Choose a reason for hiding this comment

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

That, and let's use double quotes in JSX too since most popular styleguides do that. So it'll be prop1="one".

I would also like us to use more real-world over contrived examples. Like Button or Avatar instead of MyComponent or Foo.


export default function MyRedComponent() {
return <MyComponent color="red" />;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here: could be Button and DangerButton.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK


If you don't use a JavaScript bundler and added React as a script tag, it is already in scope as a React global.

You can also refer to a React component using dot-notation from within JSX. This is convenient if you have a single module that exports many React components. For example, if `MyComponents.DatePicker` is a component, you can invoke it directly from JSX with:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: "use" rather than "invoke" because you won't actually be calling it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

return <div>Hello {props.toWhat}</div>;
}

export default function HelloWorld() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we shouldn't emphasize exports in examples unless we specifically mention module boundaries. It's fine to leave this as a function and presume that it gets rendered by something later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK****

}
```

## Props in JSX
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm conflicted about calling them props here.

If we are talking about JSX, "attributes" seems more correct. Attributes usually become props (for custom components). However key and ref are attributes obeying JSX rules that don't become props.

I don't feel strongly about this though. @spicyj What do you think?

<MyComponent message={"<3"} />
```

This behavior is usually not relevant. It's useful for `children`, but not for most props. It's only mentioned here for completeness.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: it is not obvious to me how this is useful for children, or what children "content" prop has to do with explicitly specified string literal attributes.

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 tweaked the wording a bit. AFAICT this behavior is useful so that

Foo & Bar

works the same way in HTML and in JSX - you need an unescape because JSX will re-escape it later. I'm guessing someone implemented this for children and just implemented it for all string literal props at the same time? Dunno though. Seems like a historical wart.

Copy link
Contributor

@vjeux vjeux Oct 5, 2016

Choose a reason for hiding this comment

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

Yeah, i'm not sure what children has anything to do here :)

The two times I ran into are:
(1) trying to write a "

<C prop="this is \"something\"" />

is a syntax error as the \ is not escaping the "

(2) trying to use an unicode sequence

<C prop="\u2192" />

will not display the unicode →, it's just going to display \u2192. Instead you need to do

<C prop="&#8594;" />
// or
<C prop={"\u2192"} />

var todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map(renderItem)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

An inquisitive reader would think: when don't want to do this instead of using <Item>?

In general we want to encourage people to create components rather than call functions directly. But I guess this is fine.

I don't have a good solution to this.

var todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map(renderItem)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe if we put map body inline as an arrow it is clearer that this pattern is mostly useful for one-liners.

);
}
```

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add another post-explainer here: Children passed to a custom component can be anything as long as that component transforms them into something React can understand before rendering.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK - yeah I didn't intend that part to explain functions, only to explain loops, so I turned it into a one-liner. Also added that post-explainer

You can also use the self-closing form of the tag if there are no children. So:

```js
<div className={'blorp'} />
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: "blorp"

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 just switched this to be more realistic rather than "blorp"

}

export default function BlueDatePicker() {
return <MyComponents.DatePicker color={'blue'} />;
Copy link
Contributor

Choose a reason for hiding this comment

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

="blue"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

<MyComponent message={"<3"} />
```

This behavior is usually not relevant. It's useful for `children`, but not for most props. It's only mentioned here for completeness.
Copy link
Contributor

@vjeux vjeux Oct 5, 2016

Choose a reason for hiding this comment

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

Yeah, i'm not sure what children has anything to do here :)

The two times I ran into are:
(1) trying to write a "

<C prop="this is \"something\"" />

is a syntax error as the \ is not escaping the "

(2) trying to use an unicode sequence

<C prop="\u2192" />

will not display the unicode →, it's just going to display \u2192. Instead you need to do

<C prop="&#8594;" />
// or
<C prop={"\u2192"} />

```js
<MyComponent>foo</MyComponent>

<MyComponent>{"foo"}</MyComponent>
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we use single quote for js strings

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK I just removed that "oh but this makes sense for children" comment.

@lacker lacker merged commit a73c770 into facebook:new-docs Oct 5, 2016
@vjeux
Copy link
Contributor

vjeux commented Oct 5, 2016

🎉

@lacker lacker deleted the jsx branch October 5, 2016 21:46
}
}

ReactDOM.render(React.createElement(Hello, {toWhat: 'World'}, null),
Copy link
Collaborator

Choose a reason for hiding this comment

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

fb indentation

```js
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: can we do 'Hello ', this.props.toWorld) so it's a faithful compilation?

```js
var e = React.createElement;

ReactDOM.render(e('div', null, 'Hello World'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

fb style. (I think this example might also be clearer if it defined a class since ReactDOM.render is comparatively rare.)

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.

6 participants