OSDN Git Service

Regular updates
[twpd/master.git] / react.md
1 ---
2 title: React.js
3 category: React
4 layout: 2017/sheet
5 ads: true
6 tags: [Featured]
7 updated: 2018-10-04
8 weight: -10
9 keywords:
10   - React.Component
11   - render()
12   - componentDidMount()
13   - props/state
14   - dangerouslySetInnerHTML
15 intro: |
16   [React](https://reactjs.org/) is a JavaScript library for building user interfaces. This guide targets React v15 to v16.
17 ---
18
19 {%raw%}
20
21 Components
22 ----------
23 {: .-three-column}
24
25 ### Components
26 {: .-prime}
27
28 ```jsx
29 import React from 'react'
30 import ReactDOM from 'react-dom'
31 ```
32 {: .-setup}
33
34 ```jsx
35 class Hello extends React.Component {
36   render () {
37     return <div className='message-box'>
38       Hello {this.props.name}
39     </div>
40   }
41 }
42 ```
43
44 ```jsx
45 const el = document.body
46 ReactDOM.render(<Hello name='John' />, el)
47 ```
48
49 Use the [React.js jsfiddle](http://jsfiddle.net/reactjs/69z2wepo/) to start hacking. (or the unofficial [jsbin](http://jsbin.com/yafixat/edit?js,output))
50
51 ### Import multiple exports
52 {: .-prime}
53
54 ```jsx
55 import React, {Component} from 'react'
56 import ReactDOM from 'react-dom'
57 ```
58 {: .-setup}
59
60 ```jsx
61 class Hello extends Component {
62   ...
63 }
64 ```
65
66 ### Properties
67
68 ```html
69 <Video fullscreen={true} autoplay={false} />
70 ```
71 {: .-setup}
72
73 ```jsx
74 render () {
75   this.props.fullscreen
76   const { fullscreen, autoplay } = this.props
77   ···
78 }
79 ```
80 {: data-line="2,3"}
81
82 Use `this.props` to access properties passed to the component.
83
84 See: [Properties](https://reactjs.org/docs/tutorial.html#using-props)
85
86 ### States
87
88 ```jsx
89 constructor(props) {
90   super(props)
91   this.state = { username: undefined }
92 }
93 ```
94
95 ```jsx
96 this.setState({ username: 'rstacruz' })
97 ```
98
99 ```jsx
100 render () {
101   this.state.username
102   const { username } = this.state
103   ···
104 }
105 ```
106 {: data-line="2,3"}
107
108 Use states (`this.state`) to manage dynamic data.
109
110 With [Babel](https://babeljs.io/) you can use [proposal-class-fields](https://github.com/tc39/proposal-class-fields) and get rid of constructor
111
112 ```jsx
113 class Hello extends Component {
114   state = { username: undefined };
115   ...
116 }
117 ```
118
119 See: [States](https://reactjs.org/docs/tutorial.html#reactive-state)
120
121
122 ### Nesting
123
124 ```jsx
125 class Info extends Component {
126   render () {
127     const { avatar, username } = this.props
128
129     return <div>
130       <UserAvatar src={avatar} />
131       <UserProfile username={username} />
132     </div>
133   }
134 }
135 ```
136 As of React v16.2.0, fragments can be used to return multiple children without adding extra wrapping nodes to the DOM.
137
138 ```jsx
139 import React, {
140   Component,
141   Fragment
142 } from 'react'
143
144 class Info extends Component {
145   render () {
146     const { avatar, username } = this.props
147
148     return (
149       <Fragment>
150         <UserAvatar src={avatar} />
151         <UserProfile username={username} />
152       </Fragment>
153     )
154   }
155 }
156 ```
157
158
159 {: data-line="5,6,7,8,9,10"}
160
161 Nest components to separate concerns.
162
163 See: [Composing Components](https://reactjs.org/docs/components-and-props.html#composing-components)
164
165 ### Children
166
167 ```jsx
168 <AlertBox>
169   <h1>You have pending notifications</h1>
170 </AlertBox>
171 ```
172 {: data-line="2"}
173
174 ```jsx
175 class AlertBox extends Component {
176   render () {
177     return <div className='alert-box'>
178       {this.props.children}
179     </div>
180   }
181 }
182 ```
183 {: data-line="4"}
184
185 Children are passed as the `children` property.
186
187 Defaults
188 --------
189
190 ### Setting default props
191
192 ```jsx
193 Hello.defaultProps = {
194   color: 'blue'
195 }
196 ```
197 {: data-line="1"}
198
199 See: [defaultProps](https://reactjs.org/docs/react-component.html#defaultprops)
200
201 ### Setting default state
202
203 ```jsx
204 class Hello extends Component {
205   constructor (props) {
206     super(props)
207     this.state = { visible: true }
208   }
209 }
210 ```
211 {: data-line="4"}
212
213 Set the default state in the `constructor()`.
214
215 And without constructor using [Babel](https://babeljs.io/) with [proposal-class-fields](https://github.com/tc39/proposal-class-fields).
216
217 ```jsx
218 class Hello extends Component {
219     state = { visible: true }
220   }
221 }
222 ```
223
224 {: data-line="2"}
225
226 See: [Setting the default state](https://reactjs.org/docs/react-without-es6.html#setting-the-initial-state)
227
228 Other components
229 ----------------
230 {: .-three-column}
231
232 ### Functional components
233
234 ```jsx
235 function MyComponent ({ name }) {
236   return <div className='message-box'>
237     Hello {name}
238   </div>
239 }
240 ```
241 {: data-line="1"}
242
243 Functional components have no state. Also, their `props` are passed as the first parameter to a function.
244
245 See: [Function and Class Components](https://reactjs.org/docs/components-and-props.html#functional-and-class-components)
246
247 ### Pure components
248
249 ```jsx
250 import React, {PureComponent} from 'react'
251
252 class MessageBox extends PureComponent {
253   ···
254 }
255 ```
256 {: data-line="3"}
257
258 Performance-optimized version of `React.Component`. Doesn't rerender if props/state hasn't changed.
259
260 See: [Pure components](https://reactjs.org/docs/react-api.html#react.purecomponent)
261
262 ### Component API
263
264 ```jsx
265 this.forceUpdate()
266 ```
267
268 ```jsx
269 this.setState({ ... })
270 this.setState(state => { ... })
271 ```
272
273 ```jsx
274 this.state
275 this.props
276 ```
277
278 These methods and properties are available for `Component` instances.
279
280 See: [Component API](http://facebook.github.io/react/docs/component-api.html)
281
282 Lifecycle
283 ---------
284 {: .-two-column}
285
286 ### Mounting
287
288 | Method | Description |
289 | --- | --- |
290 | `constructor` _(props)_ | Before rendering [#](https://reactjs.org/docs/react-component.html#constructor) |
291 | `componentWillMount()` | _Don't use this_ [#](https://reactjs.org/docs/react-component.html#componentwillmount) |
292 | `render()` | Render  [#](https://reactjs.org/docs/react-component.html#render) |
293 | `componentDidMount()` | After rendering (DOM available) [#](https://reactjs.org/docs/react-component.html#componentdidmount) |
294 | --- | --- |
295 | `componentWillUnmount()` | Before DOM removal [#](https://reactjs.org/docs/react-component.html#componentwillunmount) |
296 | --- | --- |
297 | `componentDidCatch()` | Catch errors (16+) [#](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html) |
298
299 Set initial the state on `constructor()`.
300 Add DOM event handlers, timers (etc) on `componentDidMount()`, then remove them on `componentWillUnmount()`.
301
302 ### Updating
303
304 | Method | Description |
305 | --- | --- |
306 | `componentDidUpdate` *(prevProps, prevState, snapshot)* | Use `setState()` here, but remember to compare props |
307 | `shouldComponentUpdate` *(newProps, newState)* | Skips `render()` if returns false |
308 | `render()` | Render |
309 | `componentDidUpdate` *(prevProps, prevState)* | Operate on the DOM here |
310
311 Called when parents change properties and `.setState()`. These are not called for initial renders.
312
313 See: [Component specs](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops)
314
315 Hooks (New)
316 -----------
317 {: .-two-column}
318
319 ### State Hook
320
321 ```jsx
322 import React, { useState } from 'react';
323
324 function Example() {
325   // Declare a new state variable, which we'll call "count"
326   const [count, setCount] = useState(0);
327
328   return (
329     <div>
330       <p>You clicked {count} times</p>
331       <button onClick={() => setCount(count + 1)}>
332         Click me
333       </button>
334     </div>
335   );
336 }
337 ```
338 {: data-line="5,10"}
339
340 Hooks are a new addition in React 16.8.
341
342 See: [Hooks at a Glance](https://reactjs.org/docs/hooks-overview.html)
343
344 ### Declaring multiple state variables
345
346 ```jsx
347 function ExampleWithManyStates() {
348   // Declare multiple state variables!
349   const [age, setAge] = useState(42);
350   const [fruit, setFruit] = useState('banana');
351   const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
352   // ...
353 }
354 ```
355
356 ### Effect hook
357
358 ```jsx
359 import React, { useState, useEffect } from 'react';
360
361 function Example() {
362   const [count, setCount] = useState(0);
363
364   // Similar to componentDidMount and componentDidUpdate:
365   useEffect(() => {
366     // Update the document title using the browser API
367     document.title = `You clicked ${count} times`;
368   });
369
370   return (
371     <div>
372       <p>You clicked {count} times</p>
373       <button onClick={() => setCount(count + 1)}>
374         Click me
375       </button>
376     </div>
377   );
378 }
379 ```
380 {: data-line="6,7,8,9,10"}
381
382 If you’re familiar with React class lifecycle methods, you can think of `useEffect` Hook as `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount` combined. 
383
384 By default, React runs the effects after every render — including the first render.
385
386 ### Building your own hooks
387
388 #### Define FriendStatus
389 ```jsx
390 import React, { useState, useEffect } from 'react';
391
392 function FriendStatus(props) {
393   const [isOnline, setIsOnline] = useState(null);
394
395   useEffect(() => {
396     function handleStatusChange(status) {
397       setIsOnline(status.isOnline);
398     }
399
400     ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
401     return () => {
402       ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
403     };
404   });
405
406   if (isOnline === null) {
407     return 'Loading...';
408   }
409   return isOnline ? 'Online' : 'Offline';
410 }
411 ```
412 {: data-line="11,12,13,14"}
413
414 Effects may also optionally specify how to “clean up” after them by returning a function. 
415
416 #### Use FriendStatus
417
418 ```jsx
419 function FriendStatus(props) {
420   const isOnline = useFriendStatus(props.friend.id);
421
422   if (isOnline === null) {
423     return 'Loading...';
424   }
425   return isOnline ? 'Online' : 'Offline';
426 }
427 ```
428 {: data-line="2"}
429
430 See: [Building Your Own Hooks](https://reactjs.org/docs/hooks-custom.html)
431
432 ### Hooks API Reference
433
434 Also see: [Hooks FAQ](https://reactjs.org/docs/hooks-faq.html)
435
436 #### Basic Hooks
437
438 | Hook                         | Description                               |
439 | ---------------------------- | ----------------------------------------- |
440 | `useState`_(initialState)_   |                                           |
441 | `useEffect`_(() => { ... })_ |                                           |
442 | `useContext`_(MyContext)_    | value returned from `React.createContext` |
443
444 Full details: [Basic Hooks](https://reactjs.org/docs/hooks-reference.html#basic-hooks)
445
446 #### Additional Hooks
447
448 | Hook                                         | Description                                                                 |
449 | -------------------------------------------- | ---------------------------------------------------------------------------- |
450 | `useReducer`_(reducer, initialArg, init)_    |                                                                              |
451 | `useCallback`_(() => { ... })_               |                                                                              |
452 | `useMemo`_(() => { ... })_                   |                                                                              |
453 | `useRef`_(initialValue)_                     |                                                                              |
454 | `useImperativeHandle`_(ref, () => { ... })_  |                                                                              |
455 | `useLayoutEffect`                            | identical to `useEffect`, but it fires synchronously after all DOM mutations |
456 | `useDebugValue`_(value)_                     | display a label for custom hooks in React DevTools                           |
457
458 Full details: [Additional Hooks](https://reactjs.org/docs/hooks-reference.html#additional-hooks)
459
460 DOM nodes
461 ---------
462 {: .-two-column}
463
464 ### References
465
466 ```jsx
467 class MyComponent extends Component {
468   render () {
469     return <div>
470       <input ref={el => this.input = el} />
471     </div>
472   }
473
474   componentDidMount () {
475     this.input.focus()
476   }
477 }
478 ```
479 {: data-line="4,9"}
480
481 Allows access to DOM nodes.
482
483 See: [Refs and the DOM](https://reactjs.org/docs/refs-and-the-dom.html)
484
485 ### DOM Events
486
487 ```jsx
488 class MyComponent extends Component {
489   render () {
490     <input type="text"
491         value={this.state.value}
492         onChange={event => this.onChange(event)} />
493   }
494
495   onChange (event) {
496     this.setState({ value: event.target.value })
497   }
498 }
499 ```
500 {: data-line="5,9"}
501
502 Pass functions to attributes like `onChange`.
503
504 See: [Events](https://reactjs.org/docs/events.html)
505
506 ## Other features
507
508 ### Transferring props
509
510 ```html
511 <VideoPlayer src="video.mp4" />
512 ```
513 {: .-setup}
514
515 ```jsx
516 class VideoPlayer extends Component {
517   render () {
518     return <VideoEmbed {...this.props} />
519   }
520 }
521 ```
522 {: data-line="3"}
523
524 Propagates `src="..."` down to the sub-component.
525
526 See [Transferring props](http://facebook.github.io/react/docs/transferring-props.html)
527
528 ### Top-level API
529
530 ```jsx
531 React.createClass({ ... })
532 React.isValidElement(c)
533 ```
534
535 ```jsx
536 ReactDOM.render(<Component />, domnode, [callback])
537 ReactDOM.unmountComponentAtNode(domnode)
538 ```
539
540 ```jsx
541 ReactDOMServer.renderToString(<Component />)
542 ReactDOMServer.renderToStaticMarkup(<Component />)
543 ```
544
545 There are more, but these are most common.
546
547 See: [React top-level API](https://reactjs.org/docs/react-api.html)
548
549 JSX patterns
550 ------------
551 {: .-two-column}
552
553 ### Style shorthand
554
555 ```jsx
556 const style = { height: 10 }
557 return <div style={style}></div>
558 ```
559
560 ```jsx
561 return <div style={{ margin: 0, padding: 0 }}></div>
562 ```
563
564 See: [Inline styles](https://reactjs.org/tips/inline-styles.html)
565
566 ### Inner HTML
567
568 ```jsx
569 function markdownify() { return "<p>...</p>"; }
570 <div dangerouslySetInnerHTML={{__html: markdownify()}} />
571 ```
572
573 See: [Dangerously set innerHTML](https://reactjs.org/tips/dangerously-set-inner-html.html)
574
575 ### Lists
576
577 ```jsx
578 class TodoList extends Component {
579   render () {
580     const { items } = this.props
581
582     return <ul>
583       {items.map(item =>
584         <TodoItem item={item} key={item.key} />)}
585     </ul>
586   }
587 }
588 ```
589 {: data-line="6,7"}
590
591 Always supply a `key` property.
592
593 ### Conditionals
594
595 ```jsx
596 <Fragment>
597   {showMyComponent
598     ? <MyComponent />
599     : <OtherComponent />}
600 </Fragment>
601 ```
602
603 ### Short-circuit evaluation
604
605 ```jsx
606 <Fragment>
607   {showPopup && <Popup />}
608   ...
609 </Fragment>
610 ```
611
612 New features
613 ------------
614 {: .-three-column}
615
616 ### Returning multiple elements
617
618 You can return multiple elements as arrays or fragments.
619
620 #### Arrays
621
622 ```js
623 render () {
624   // Don't forget the keys!
625   return [
626     <li key="A">First item</li>,
627     <li key="B">Second item</li>
628   ]
629 }
630 ```
631 {: data-line="3,4,5,6"}
632
633 #### Fragments
634 ```js
635 render () {
636   // Fragments don't require keys!
637   return (
638     <Fragment>
639       <li>First item</li>
640       <li>Second item</li>
641     </Fragment>
642   )
643 }
644 ```
645 {: data-line="3,4,5,6,7,8"}
646
647 See: [Fragments and strings](https://reactjs.org/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings)
648
649 ### Returning strings
650
651 ```js
652 render() {
653   return 'Look ma, no spans!';
654 }
655 ```
656 {: data-line="2"}
657
658 You can return just a string.
659
660 See: [Fragments and strings](https://reactjs.org/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings)
661
662 ### Errors
663
664 ```js
665 class MyComponent extends Component {
666   ···
667   componentDidCatch (error, info) {
668     this.setState({ error })
669   }
670 }
671 ```
672 {: data-line="3,4,5"}
673
674 Catch errors via `componentDidCatch`. (React 16+)
675
676 See: [Error handling in React 16](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html)
677
678 ### Portals
679
680 ```js
681 render () {
682   return React.createPortal(
683     this.props.children,
684     document.getElementById('menu')
685   )
686 }
687 ```
688 {: data-line="2,3,4,5"}
689
690 This renders `this.props.children` into any location in the DOM.
691
692 See: [Portals](https://reactjs.org/docs/portals.html)
693
694 ### Hydration
695
696 ```js
697 const el = document.getElementById('app')
698 ReactDOM.hydrate(<App />, el)
699 ```
700 {: data-line="2"}
701
702 Use `ReactDOM.hydrate` instead of using `ReactDOM.render` if you're rendering over the output of [ReactDOMServer](https://reactjs.org/docs/react-dom-server.html).
703
704 See: [Hydrate](https://reactjs.org/docs/react-dom.html#hydrate)
705
706 Property validation
707 -------------------
708 {: .-three-column}
709
710 ### PropTypes
711
712 ```js
713 import PropTypes from 'prop-types'
714 ```
715 {: .-setup}
716
717 See: [Typechecking with PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html)
718
719 | `any`                     | Anything                             |
720
721 #### Basic
722
723 | `string`                  |                                      |
724 | `number`                  |                                      |
725 | `func`                    | Function                             |
726 | `bool`                    | True or false                        |
727
728 #### Enum
729
730 | `oneOf`_(any)_            | Enum types                           |
731 | `oneOfType`_(type array)_ | Union                                |
732
733 #### Array
734
735 | `array`                   |                                      |
736 | `arrayOf`_(...)_          |                                      |
737
738 #### Object
739
740 | `object`                  |                                      |
741 | `objectOf`_(...)_         | Object with values of a certain type |
742 | `instanceOf`_(...)_       | Instance of a class                  |
743 | `shape`_(...)_            |                                      |
744
745 #### Elements
746
747 | `element`                 | React element                        |
748 | `node`                    | DOM node                             |
749
750 #### Required
751
752 | `(···).isRequired`        | Required                             |
753
754 ### Basic types
755
756 ```jsx
757 MyComponent.propTypes = {
758   email:      PropTypes.string,
759   seats:      PropTypes.number,
760   callback:   PropTypes.func,
761   isClosed:   PropTypes.bool,
762   any:        PropTypes.any
763 }
764 ```
765
766 ### Required types
767
768 ```jsx
769 MyCo.propTypes = {
770   name:  PropTypes.string.isRequired
771 }
772 ```
773
774 ### Elements
775
776 ```jsx
777 MyCo.propTypes = {
778   // React element
779   element: PropTypes.element,
780
781   // num, string, element, or an array of those
782   node: PropTypes.node
783 }
784 ```
785
786 ### Enumerables (oneOf)
787
788 ```jsx
789 MyCo.propTypes = {
790   direction: PropTypes.oneOf([
791     'left', 'right'
792   ])
793 }
794 ```
795
796 ### Arrays and objects
797
798 ```jsx
799 MyCo.propTypes = {
800   list: PropTypes.array,
801   ages: PropTypes.arrayOf(PropTypes.number),
802   user: PropTypes.object,
803   user: PropTypes.objectOf(PropTypes.number),
804   message: PropTypes.instanceOf(Message)
805 }
806 ```
807
808 ```jsx
809 MyCo.propTypes = {
810   user: PropTypes.shape({
811     name: PropTypes.string,
812     age:  PropTypes.number
813   })
814 }
815 ```
816
817 Use `.array[Of]`, `.object[Of]`, `.instanceOf`, `.shape`.
818
819 ### Custom validation
820
821 ```jsx
822 MyCo.propTypes = {
823   customProp: (props, key, componentName) => {
824     if (!/matchme/.test(props[key])) {
825       return new Error('Validation failed!')
826     }
827   }
828 }
829 ```
830
831 Also see
832 --------
833
834 * [React website](https://reactjs.org) _(reactjs.org)_
835 * [React cheatsheet](https://reactcheatsheet.com/) _(reactcheatsheet.com)_
836 * [Awesome React](https://github.com/enaqx/awesome-react) _(github.com)_
837 * [React v0.14 cheatsheet](react@0.14) _Legacy version_
838
839 {%endraw%}