Browse Source

Add more highlighting to docs (#8076)

* Tweak JSX in Depth

* Add highlighting to Refs and the DOM

* More tweaks
main
Dan Abramov 8 years ago
committed by GitHub
parent
commit
16d8bd1ff6
  1. 169
      docs/jsx-in-depth.md
  2. 27
      docs/refs-and-the-dom.md

169
docs/jsx-in-depth.md

@ -14,13 +14,19 @@ redirect_from:
Fundamentally, JSX just provides syntactic sugar for the `React.createElement(component, props, ...children)` function. The JSX code:
```js
<MyButton color="blue" shadowSize={2}>Click Me</MyButton>
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
```
compiles into:
```js
React.createElement(MyButton, {color: "blue", shadowSize: 2}, 'Click Me')
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
```
You can also use the self-closing form of the tag if there are no children. So:
@ -32,7 +38,11 @@ You can also use the self-closing form of the tag if there are no children. So:
compiles into:
```js
React.createElement('div', {className: 'sidebar'}, null)
React.createElement(
'div',
{className: 'sidebar'},
null
)
```
If you want to test out how some specific JSX is converted into JavaScript, you can try out [the online Babel compiler](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-0&code=function%20hello()%20%7B%0A%20%20return%20%3Cdiv%3EHello%20world!%3C%2Fdiv%3E%3B%0A%7D).
@ -43,29 +53,34 @@ The first part of a JSX tag determines the type of the React element.
Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX `<Foo />` expression, `Foo` must be in scope.
### React Must Be in Scope
Since JSX compiles into calls to `React.createElement`, the `React` library must also always be in scope from your JSX code.
For example, both of the imports are necessary in this code, even though 'React' and 'CustomButton' are not directly referenced from JavaScript:
For example, both of the imports are necessary in this code, even though `React` and `CustomButton` are not directly referenced from JavaScript:
```js
```js{1,2,5}
import React from 'react';
import CustomButton from './CustomButton';
function WarningButton() {
// return React.createElement(CustomButton, {color: 'red'}, null);
return <CustomButton color="red" />;
}
```
If you don't use a JavaScript bundler and added React as a script tag, it is already in scope as a React global.
If you don't use a JavaScript bundler and added React as a script tag, it is already in scope as a `React` global.
### Using Dot Notation for JSX Type
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 use it directly from JSX with:
```js
```js{10}
import React from 'react';
const MyComponents = {
DatePicker: function(props) {
return <div>imagine a {props.color} datepicker here</div>;
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
@ -74,47 +89,80 @@ function BlueDatePicker() {
}
```
### User-Defined Components Must Be Capitalized
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.
For example, this code will not run as expected:
```js
```js{3,4,10,11}
import React from 'react';
// Wrong! This is a component and should have been capitalized:
function hello(props) {
// This use of <div> is legitimate because div is a valid HTML tag
// Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// This code attempts to create an HTML <hello> tag and fails
// Wrong! React thinks <hello /> is an HTML tag because it's not capitalized:
return <hello toWhat="World" />;
}
```
To fix this, we will rename `hello` to `Hello` and use `<Hello />` when referring to it:
```js{3,4,10,11}
import React from 'react';
// Correct! This is a component and should be capitalized:
function Hello(props) {
// Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Correct! React knows <Hello /> is a component because it's capitalized.
return <Hello toWhat="World" />;
}
```
### Choosing the Type at Runtime
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. This often comes up when you want to render a different component based on a prop:
```js
```js{10,11}
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: <PhotoStory />,
video: <VideoStory />,
photo: PhotoStory,
video: VideoStory
};
function Story1(props) {
// Not valid JSX
return <components[props.story] />;
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}
```
function render2(props) {
const MyComponent = components[props.story];
To fix this, we will assign the type to a capitalized variable first:
// Valid JSX
return <MyComponent />;
```js{9-11}
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
```
@ -134,7 +182,7 @@ For `MyComponent`, The value of `props.foo` will be `10` because the expression
`if` statements and `for` loops are not expressions in JavaScript, so they can't be used in JSX directly. Instead, you can put these in the surrounding code. For example:
```js
```js{3-7}
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
@ -153,7 +201,7 @@ You can pass a string literal as a prop. These two JSX expressions are equivalen
```js
<MyComponent message="hello world" />
<MyComponent message={"hello world"} />
<MyComponent message={'hello world'} />
```
When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:
@ -161,7 +209,7 @@ When you pass a string literal, its value is HTML-unescaped. So these two JSX ex
```js
<MyComponent message="&lt;3" />
<MyComponent message={"<3"} />
<MyComponent message={'<3'} />
```
This behavior is usually not relevant. It's only mentioned here for completeness.
@ -176,20 +224,20 @@ If you pass no value for a prop, it defaults to `true`. These two JSX expression
<MyTextBox autocomplete={true} />
```
In general, we don't recommend using this because it can be confused with the ES6 object shorthand `{foo}` which is short for {foo: foo} rather than `{foo: true}`. This behavior is just there so that it matches the behavior of HTML.
In general, we don't recommend using this because it can be confused with the [ES6 object shorthand](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015) `{foo}` which is short for `{foo: foo}` rather than `{foo: true}`. This behavior is just there so that it matches the behavior of HTML.
### Spread Attributes
If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a "spread" operator to pass the whole props object. These two render functions are equivalent:
If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a "spread" operator to pass the whole props object. These two components are equivalent:
```js
function render1() {
const props = {left: 'ben', right: 'hector'};
return <MyComponent {...props} />;
```js{7}
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function render2() {
return <MyComponent left="ben" right="hector" />;
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
```
@ -270,12 +318,12 @@ You can pass any JavaScript expression as children, by enclosing it within `{}`.
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
```js
```js{2,9}
function Item(props) {
return <li>{props.message}</li>;
}
function renderTodoList() {
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
@ -287,15 +335,17 @@ function renderTodoList() {
JavaScript expressions can be mixed with other types of children. This is often useful in lieu of string templates:
```js
```js{2}
function Hello(props) {
return <div>Hello {props.addressee}!</div>;
}
```
### Functions as Children
Normally, JavaScript expressions inserted in JSX will evaluate to a string, a React element, or a list of those things. However, `props.children` works just like any other prop in that it can pass any sort of data, not just the sorts that React knows how to render. For example, if you have a custom component, you could have it take a callback as `props.children`:
```js
```js{4,13}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
@ -307,16 +357,18 @@ function ListOfTenThings() {
// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < numTimes; i++) {
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>
return <div>{items}</div>;
}
```
Children passed to a custom component can be anything, as long as that component transforms them into something React can understand before rendering. This usage is not common, but it works if you want to stretch what JSX is capable of.
`false`, `null`, 'undefined', and 'true' are valid children. They simply don't render. These JSX expressions will all render to the same thing:
### Booleans, Null, and Undefined Are Ignored
`false`, `null`, `undefined`, and `true` are valid children. They simply don't render. These JSX expressions will all render to the same thing:
```js
<div />
@ -330,8 +382,39 @@ Children passed to a custom component can be anything, as long as that component
<div>{true}</div>
```
This can be useful to conditionally render React elements. This JSX only renders a `<Header />` if `showHeader` is true:
This can be useful to conditionally render React elements. This JSX only renders a `<Header />` if `showHeader` is `true`:
```js
<div>{showHeader && <Header />}<Content /></div>
```js{2}
<div>
{showHeader && <Header />}
<Content />
</div>
```
One caveat is that some ["falsy" values](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), such as the `0` number, are still rendered by React. For example, this code will not behave as you might expect because `0` will be printed when `props.messages` is an empty array:
```js{2}
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>
```
To fix this, make sure that the expression before `&&` is always boolean:
```js{2}
<div>
{props.messages.length > 0 &&
<MessageList messages={props.messages} />
}
</div>
```
Conversely, if you want a value like `false`, `true`, `null`, or `undefined` to appear in the output, you have to [convert it to a string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#String_conversion) first:
```js{2}
<div>
My JavaScript variable is {String(myVariable)}.
</div>
```

27
docs/refs-and-the-dom.md

@ -15,9 +15,9 @@ In the typical React dataflow, [props](/react/docs/components-and-props.html) ar
React supports a special attribute that you can attach to any component. The `ref` attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.
When the `ref` attribute is used on a HTML element, the `ref` callback receives the underlying DOM element as its argument. For example, this code uses the `ref` callback to store a reference to a DOM node:
When the `ref` attribute is used on an HTML element, the `ref` callback receives the underlying DOM element as its argument. For example, this code uses the `ref` callback to store a reference to a DOM node:
```javascript
```javascript{8,9,19}
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
@ -31,10 +31,12 @@ class CustomTextInput extends React.Component {
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in this.textInput
// element in this.textInput.
return (
<div>
<input type="text" ref={(input) => this.textInput = input} />
<input
type="text"
ref={(input) => this.textInput = input} />
<input
type="button"
value="Focus the text input"
@ -52,24 +54,27 @@ Using the `ref` callback just to set a property on the class is a common pattern
When the `ref` attribute is used on a custom component, the `ref` callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting:
```javascript
```javascript{3,9}
class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return <CustomTextInput ref={(input) => this.textInput = input} />;
return (
<CustomTextInput
ref={(input) => this.textInput = input} />
);
}
}
```
You may not use the `ref` attribute on functional components because they don't have instances. You can, however, use the `ref` attribute inside the `render` function of a functional component:
```javascript
```javascript{2,3,6,13}
function CustomTextInput(props) {
// textInput must be declared here so the ref callback can refer to it
let textInput;
let textInput = null;
function handleClick() {
textInput.focus();
@ -77,7 +82,9 @@ function CustomTextInput(props) {
return (
<div>
<input type="text" ref={(input) => textInput = input} />
<input
type="text"
ref={(input) => textInput = input} />
<input
type="button"
value="Focus the text input"
@ -90,4 +97,4 @@ function CustomTextInput(props) {
### Don't Overuse Refs
Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy - see the [Lifting State Up](/react/docs/lifting-state-up.html) guide for examples of this.
Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. See the [Lifting State Up](/react/docs/lifting-state-up.html) guide for examples of this.

Loading…
Cancel
Save