├── README.md
├── chapter-03
├── .gitignore
└── reusable-components
│ ├── .eslintrc
│ ├── .gitignore
│ ├── .storybook
│ └── config.js
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ │ ├── item.js
│ │ ├── list.js
│ │ ├── post-list.js
│ │ └── user-list.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
│ └── stories
│ └── list.js
├── chapter-04
├── container-presentational
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── geolocation
│ │ │ ├── geolocation-container.js
│ │ │ ├── geolocation.js
│ │ │ └── index.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── higher-order-components
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ ├── my-component.js
│ └── with-inner-width.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── chapter-05
├── data-fetching
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── list.js
│ │ └── with-data.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── data-flow
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── buttons.js
│ │ ├── counter.js
│ │ └── display.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── react-refetch
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ ├── gist.js
│ └── list.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── chapter-06
├── controlled-components
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── controlled.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── css-transition-group
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── transition.css
│ │ └── transition.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── event-switch
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── button.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── json-schema
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── json-schema-form.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── react-motion
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── transition.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── refs-dom
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── focus.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── refs-instance
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── input.js
│ │ └── reset.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── svg
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── circle.js
│ │ └── red-circle.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── uncontrolled-components
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ └── uncontrolled.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── chapter-07
├── css-modules
│ ├── .eslintrc
│ ├── .gitignore
│ ├── index.css
│ ├── index.js
│ ├── package.json
│ └── webpack.config.js
├── inline-styles
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── font-size.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── radium
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── button.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── styled-components
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ └── button.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── chapter-08
├── data-fetching
│ ├── .eslintrc
│ ├── .gitignore
│ ├── package.json
│ ├── src
│ │ ├── app.js
│ │ ├── client.js
│ │ ├── server.js
│ │ └── template.js
│ └── webpack.config.js
├── next
│ ├── .eslintrc
│ ├── .gitignore
│ ├── package.json
│ └── pages
│ │ └── index.js
└── server-side-rendering
│ ├── .eslintrc
│ ├── .gitignore
│ ├── package.json
│ ├── src
│ ├── app.js
│ ├── client.js
│ ├── server.js
│ └── template.js
│ └── webpack.config.js
├── chapter-09
├── constants-props
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── item.js
│ │ └── list.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── creating-functions
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── item.js
│ │ └── list.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── good-design
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── form.js
│ │ ├── list.js
│ │ └── todos.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── keys
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ └── list.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── chapter-10
├── enzyme
│ ├── .babelrc
│ ├── .eslintrc
│ ├── .gitignore
│ ├── button.js
│ ├── button.spec.js
│ └── package.json
├── higher-order-components
│ ├── .babelrc
│ ├── .eslintrc
│ ├── .gitignore
│ ├── __snapshots__
│ │ └── list.spec.js.snap
│ ├── get-json.js
│ ├── list.js
│ ├── list.spec.js
│ ├── package.json
│ ├── with-data.js
│ └── with-data.spec.js
├── jest
│ ├── .babelrc
│ ├── .eslintrc
│ ├── .gitignore
│ ├── button.js
│ ├── button.spec.js
│ └── package.json
├── mocha
│ ├── .babelrc
│ ├── .eslintrc
│ ├── .gitignore
│ ├── button.js
│ ├── package.json
│ └── test
│ │ └── button.spec.js
├── page-object
│ ├── .babelrc
│ ├── .eslintrc
│ ├── .gitignore
│ ├── form.js
│ ├── form.spec.js
│ ├── package.json
│ └── page.js
└── real-world
│ ├── .babelrc
│ ├── .gitignore
│ ├── TodoTextInput-snapshot.spec.js
│ ├── TodoTextInput.js
│ ├── TodoTextInput.spec.js
│ ├── __snapshots__
│ └── TodoTextInput-snapshot.spec.js.snap
│ └── package.json
├── chapter-11
├── index-as-key
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── list.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
├── initializing-state
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ └── counter.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── mutating-state
│ ├── .eslintrc
│ ├── .gitignore
│ ├── README.md
│ ├── favicon.ico
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ ├── counter.js
│ └── list.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
└── cover.jpg
/README.md:
--------------------------------------------------------------------------------
1 | # React Design Patterns and Best Practices
2 | Build modular applications that are easy to scale using the most powerful components and design
3 | patterns that React can offer you right now
4 |
5 | [https://www.packtpub.com/web-development/react-design-patterns-and-best-practices](https://www.packtpub.com/web-development/react-design-patterns-and-best-practices)
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/chapter-03/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-03/.gitignore
--------------------------------------------------------------------------------
/chapter-03/reusable-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@kadira/storybook'
2 |
3 | function loadStories() {
4 | require('../stories/list')
5 | }
6 |
7 | configure(loadStories, module)
8 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-03/reusable-components/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/reusable-components/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "@kadira/storybook": "^2.3.0",
7 | "eslint": "^2.9.0",
8 | "eslint-config-airbnb": "^9.0.1",
9 | "eslint-plugin-import": "^1.7.0",
10 | "eslint-plugin-jsx-a11y": "^1.2.0",
11 | "eslint-plugin-react": "^5.0.1",
12 | "react-scripts": "0.2.2"
13 | },
14 | "dependencies": {
15 | "react": "^15.3.1",
16 | "react-dom": "^15.3.1"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src",
23 | "storybook": "start-storybook -p 9001"
24 | },
25 | "eslintConfig": {
26 | "extends": "./node_modules/react-scripts/config/eslint.js"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import PostList from './components/post-list'
6 | import UserList from './components/user-list'
7 |
8 | class App extends Component {
9 | render() {
10 | return (
11 |
12 |
13 |

14 |
Welcome to React
15 |
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | export default App
24 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/components/item.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Item = ({ text, title }) => (
4 |
5 | {title}
6 | {text && {text}
}
7 |
8 | )
9 |
10 | Item.propTypes = {
11 | text: React.PropTypes.string,
12 | title: React.PropTypes.string,
13 | }
14 |
15 | export default Item
16 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Item from './item'
3 |
4 | const List = ({ collection, textKey, titleKey }) => (
5 |
6 | {collection.map(item =>
7 |
8 | )}
9 |
10 | )
11 |
12 | List.propTypes = {
13 | collection: React.PropTypes.array,
14 | textKey: React.PropTypes.string,
15 | titleKey: React.PropTypes.string,
16 | }
17 |
18 | export default List
19 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/components/post-list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import List from './list'
3 |
4 | const Posts = {
5 | fetch() {
6 | return new Promise(resolve => resolve([{ id: 1, title: 'title', excerpt: 'excerpt' }]))
7 | },
8 | }
9 |
10 | class PostList extends React.Component {
11 |
12 | constructor(props) {
13 | super(props)
14 |
15 | this.state = {
16 | posts: [],
17 | }
18 | }
19 |
20 | componentDidMount() {
21 | Posts.fetch().then(posts => {
22 | this.setState({ posts })
23 | })
24 | }
25 |
26 | render() {
27 | return (
28 |
29 | )
30 | }
31 |
32 | }
33 |
34 | export default PostList
35 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/components/user-list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import List from './list'
3 |
4 | const UserList = ({ users }) => (
5 |
6 | )
7 |
8 | UserList.propTypes = {
9 | users: React.PropTypes.array,
10 | }
11 |
12 | export default UserList
13 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-03/reusable-components/stories/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@kadira/storybook'
3 | import List from '../src/components/list'
4 |
5 | const users = [{ id: 1, username: 'username', bio: 'bio' }]
6 |
7 | storiesOf('List', module)
8 | .add('with bio', () => (
9 |
10 | ))
11 | .add('without bio', () => (
12 |
13 | ))
14 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-04/container-presentational/favicon.ico
--------------------------------------------------------------------------------
/chapter-04/container-presentational/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Geolocation from './components/geolocation'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/components/geolocation/geolocation-container.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Geolocation from './geolocation'
3 |
4 | class GeolocationContainer extends React.Component {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.state = {
10 | latitude: null,
11 | longitude: null,
12 | }
13 |
14 | this.handleSuccess = this.handleSuccess.bind(this)
15 | }
16 |
17 | componentDidMount() {
18 | if (navigator.geolocation) {
19 | navigator.geolocation.getCurrentPosition(this.handleSuccess)
20 | }
21 | }
22 |
23 | handleSuccess({ coords }) {
24 | this.setState({
25 | latitude: coords.latitude,
26 | longitude: coords.longitude,
27 | })
28 | }
29 |
30 | render() {
31 | return (
32 |
33 | )
34 | }
35 |
36 | }
37 |
38 | export default GeolocationContainer
39 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/components/geolocation/geolocation.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Geolocation = ({ latitude, longitude }) => (
4 |
5 |
Latitude: {latitude}
6 |
Longitude: {longitude}
7 |
8 | )
9 |
10 | Geolocation.propTypes = {
11 | latitude: React.PropTypes.number,
12 | longitude: React.PropTypes.number,
13 | }
14 |
15 | export default Geolocation
16 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/components/geolocation/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './geolocation-container'
2 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-04/container-presentational/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-04/higher-order-components/favicon.ico
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import MyComponent from './components/my-component'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/components/my-component.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import withInnerWidth from './with-inner-width'
4 |
5 | const MyComponent = ({ innerWidth }) => innerWidth: {innerWidth}
6 |
7 | MyComponent.propTypes = {
8 | innerWidth: React.PropTypes.number,
9 | }
10 |
11 | export default withInnerWidth(MyComponent)
12 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/components/with-inner-width.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const withInnerWidth = Component => (
4 | class extends React.Component {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.state = {
10 | innerWidth: window.innerWidth,
11 | }
12 |
13 | this.handleResize = this.handleResize.bind(this)
14 | }
15 |
16 | componentDidMount() {
17 | window.addEventListener('resize', this.handleResize)
18 | }
19 |
20 | componentWillUnmount() {
21 | window.removeEventListener('resize', this.handleResize)
22 | }
23 |
24 | handleResize() {
25 | this.setState({
26 | innerWidth: window.innerWidth,
27 | })
28 | }
29 |
30 | render() {
31 | return
32 | }
33 |
34 | }
35 | )
36 |
37 | export default withInnerWidth
38 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-04/higher-order-components/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-05/data-fetching/favicon.ico
--------------------------------------------------------------------------------
/chapter-05/data-fetching/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import List from './components/list'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import withData from './with-data'
3 |
4 | const List = ({ data: gists }) => (
5 |
6 | {gists.map(gist => (
7 | - {gist.description}
8 | ))}
9 |
10 | )
11 |
12 | List.propTypes = {
13 | data: React.PropTypes.array,
14 | }
15 |
16 | const withGists = withData(props => `https://api.github.com/users/${props.username}/gists`)
17 |
18 | export default withGists(List)
19 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/components/with-data.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const withData = url => Component => (
4 | class extends React.Component {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.state = { data: [] }
10 | }
11 |
12 | componentDidMount() {
13 | const endpoint = typeof url === 'function' ? url(this.props) : url
14 |
15 | fetch(endpoint)
16 | .then(response => response.json())
17 | .then(data => this.setState({ data }))
18 | }
19 |
20 | render() {
21 | return
22 | }
23 | }
24 | )
25 |
26 | export default withData
27 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-05/data-fetching/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-05/data-flow/favicon.ico
--------------------------------------------------------------------------------
/chapter-05/data-flow/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Counter from './components/counter'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/components/buttons.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Buttons = ({ onDecrement, onIncrement }) => (
4 |
5 |
6 |
7 |
8 | )
9 |
10 | Buttons.propTypes = {
11 | onDecrement: React.PropTypes.func,
12 | onIncrement: React.PropTypes.func,
13 | }
14 |
15 | export default Buttons
16 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/components/counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Display from './display'
3 | import Buttons from './buttons'
4 |
5 | class Counter extends React.Component {
6 |
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = {
11 | counter: 0,
12 | }
13 |
14 | this.handleIncrement = this.handleIncrement.bind(this)
15 | this.handleDecrement = this.handleDecrement.bind(this)
16 | }
17 |
18 | handleIncrement() {
19 | this.setState({
20 | counter: this.state.counter + 1,
21 | })
22 | }
23 |
24 | handleDecrement() {
25 | this.setState({
26 | counter: this.state.counter - 1,
27 | })
28 | }
29 |
30 | render() {
31 | return (
32 |
33 |
34 |
38 |
39 | )
40 | }
41 |
42 | }
43 |
44 | export default Counter
45 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/components/display.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Display = ({ counter }) => {counter}
4 |
5 | Display.propTypes = {
6 | counter: React.PropTypes.number,
7 | }
8 |
9 | export default Display
10 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-05/data-flow/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-05/react-refetch/favicon.ico
--------------------------------------------------------------------------------
/chapter-05/react-refetch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1",
16 | "react-refetch": "^1.0.0-beta.8"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import List from './components/list'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/components/gist.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-refetch'
3 |
4 | const Gist = ({ description, star }) => (
5 |
6 | {description}
7 |
8 |
9 | )
10 |
11 | Gist.propTypes = {
12 | description: React.PropTypes.string,
13 | star: React.PropTypes.func,
14 | }
15 |
16 | const token = 'access_token=123'
17 |
18 | const connectWithStar = connect(({ id }) => ({
19 | star: () => ({
20 | starResponse: {
21 | url: `https://api.github.com/gists/${id}/star?${token}`,
22 | method: 'PUT',
23 | },
24 | }),
25 | }))
26 |
27 | export default connectWithStar(Gist)
28 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-refetch'
3 | import Gist from './gist'
4 |
5 | const List = ({ gists }) => (
6 | gists.fulfilled && (
7 |
8 | {gists.value.map(gist => (
9 |
10 | ))}
11 |
12 | )
13 | )
14 |
15 | List.propTypes = {
16 | gists: React.PropTypes.object,
17 | }
18 |
19 | const connectWithGists = connect(({ username }) => ({
20 | gists: `https://api.github.com/users/${username}/gists`,
21 | }))
22 |
23 | export default connectWithGists(List)
24 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-05/react-refetch/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/controlled-components/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/controlled-components/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Controlled from './components/controlled'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/src/components/controlled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Controlled extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | firstName: 'Dan',
10 | lastName: 'Abramov',
11 | }
12 |
13 | this.handleChange = this.handleChange.bind(this)
14 | this.handleSubmit = this.handleSubmit.bind(this)
15 | }
16 |
17 | handleChange({ target }) {
18 | this.setState({
19 | [target.name]: target.value,
20 | })
21 | }
22 |
23 | handleSubmit(e) {
24 | e.preventDefault()
25 |
26 | console.log(`${this.state.firstName} ${this.state.lastName}`)
27 | }
28 |
29 | render() {
30 | return (
31 |
46 | )
47 | }
48 |
49 | }
50 |
51 | export default Controlled
52 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/controlled-components/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/css-transition-group/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-addons-css-transition-group": "^15.3.2",
16 | "react-dom": "^15.3.1"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Transition from './components/transition'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/components/transition.css:
--------------------------------------------------------------------------------
1 | .fade-appear {
2 | opacity: 0.01;
3 | }
4 |
5 | .fade-appear.fade-appear-active {
6 | opacity: 1;
7 | transition: opacity .5s ease-in;
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/components/transition.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
3 | import './transition.css'
4 |
5 | const Transition = () => (
6 |
11 | Hello React
12 |
13 | )
14 |
15 | export default Transition
16 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/css-transition-group/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/event-switch/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/event-switch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Button from './components/button'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/components/button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Button extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.handleEvent = this.handleEvent.bind(this)
9 | }
10 |
11 | handleEvent(event) {
12 | switch (event.type) {
13 | case 'click':
14 | console.log('clicked')
15 | break
16 |
17 | case 'dblclick':
18 | console.log('double clicked')
19 | break
20 |
21 | default:
22 | console.log('unhandled', event.type)
23 | }
24 | }
25 |
26 | render() {
27 | return (
28 |
29 | )
30 | }
31 |
32 | }
33 |
34 | export default Button
35 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/event-switch/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/json-schema/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/json-schema/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1",
16 | "react-jsonschema-form": "^0.40.0"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import JSONSchemaForm from './components/json-schema-form'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/components/json-schema-form.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Form from 'react-jsonschema-form'
3 |
4 | const schema = {
5 | type: 'object',
6 | properties: {
7 | firstName: { type: 'string', default: 'Dan' },
8 | lastName: { type: 'string', default: 'Abramov' },
9 | },
10 | }
11 |
12 | class JSONSchemaForm extends React.Component {
13 |
14 | constructor(props) {
15 | super(props)
16 |
17 | this.handleSubmit = this.handleSubmit.bind(this)
18 | }
19 |
20 | handleSubmit({ formData }) {
21 | console.log(formData)
22 | }
23 |
24 | render() {
25 | return (
26 |
27 | )
28 | }
29 |
30 | }
31 |
32 | export default JSONSchemaForm
33 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/json-schema/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/react-motion/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/react-motion/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1",
16 | "react-motion": "^0.4.5"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Transition from './components/transition'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/components/transition.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Motion, spring } from 'react-motion'
3 |
4 | const Transition = () => (
5 |
6 | {interpolatingStyle => (
7 | Hello React
8 | )}
9 |
10 | )
11 |
12 | export default Transition
13 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/react-motion/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/refs-dom/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/refs-dom/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Focus from './components/focus'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/components/focus.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Focus extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.handleClick = this.handleClick.bind(this)
9 | }
10 |
11 | handleClick() {
12 | this.element.focus()
13 | }
14 |
15 | render() {
16 | return (
17 |
18 | (this.element = element)} />
19 |
20 |
21 | )
22 | }
23 |
24 | }
25 |
26 | export default Focus
27 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/refs-dom/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/refs-instance/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/refs-instance/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Reset from './components/reset'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/components/input.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Input extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | value: '',
10 | }
11 |
12 | this.reset = this.reset.bind(this)
13 | this.handleChange = this.handleChange.bind(this)
14 | }
15 |
16 | reset() {
17 | this.setState({
18 | value: '',
19 | })
20 | }
21 |
22 | handleChange({ target }) {
23 | this.setState({
24 | value: target.value,
25 | })
26 | }
27 |
28 | render() {
29 | return (
30 |
31 | )
32 | }
33 |
34 | }
35 |
36 | export default Input
37 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/components/reset.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Input from './input'
3 |
4 | class Reset extends React.Component {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.handleClick = this.handleClick.bind(this)
10 | }
11 |
12 | handleClick(e) {
13 | e.preventDefault()
14 |
15 | this.element.reset()
16 | }
17 |
18 | render() {
19 | return (
20 |
24 | )
25 | }
26 |
27 | }
28 |
29 | export default Reset
30 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/refs-instance/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/svg/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/svg/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/svg/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/svg/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/svg/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/svg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import RedCircle from './components/red-circle'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/components/circle.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Circle = ({ x, y, radius, fill }) => (
4 |
7 | )
8 |
9 | Circle.propTypes = {
10 | x: React.PropTypes.number,
11 | y: React.PropTypes.number,
12 | radius: React.PropTypes.number,
13 | fill: React.PropTypes.string,
14 | }
15 |
16 | export default Circle
17 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/components/red-circle.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Circle from './circle'
3 |
4 | const RedCircle = ({ x, y, radius }) => (
5 |
6 | )
7 |
8 | RedCircle.propTypes = {
9 | x: React.PropTypes.number,
10 | y: React.PropTypes.number,
11 | radius: React.PropTypes.number,
12 | }
13 |
14 | export default RedCircle
15 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-06/svg/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-06/uncontrolled-components/favicon.ico
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Uncontrolled from './components/uncontrolled'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/src/components/uncontrolled.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Uncontrolled extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | firstName: '',
10 | lastName: '',
11 | }
12 |
13 | this.handleChange = this.handleChange.bind(this)
14 | this.handleSubmit = this.handleSubmit.bind(this)
15 | }
16 |
17 | handleChange({ target }) {
18 | this.setState({
19 | [target.name]: target.value,
20 | })
21 | }
22 |
23 | handleSubmit(e) {
24 | e.preventDefault()
25 |
26 | console.log(`${this.state.firstName} ${this.state.lastName}`)
27 | }
28 |
29 | render() {
30 | return (
31 |
36 | )
37 | }
38 |
39 | }
40 |
41 | export default Uncontrolled
42 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-06/uncontrolled-components/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/index.css:
--------------------------------------------------------------------------------
1 | .background-red {
2 | background-color: #ff0000;
3 | }
4 |
5 | .button {
6 | composes: background-red;
7 | width: 320px;
8 | padding: 20px;
9 | border-radius: 5px;
10 | border: none;
11 | outline: none;
12 | }
13 |
14 | .button:hover {
15 | color: #fff;
16 | }
17 |
18 | .button:active {
19 | position: relative;
20 | top: 2px;
21 | }
22 |
23 | @media (max-width: 480px) {
24 | .button {
25 | width: 160px
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import cssModules from 'react-css-modules'
4 | import styles from './index.css'
5 |
6 | const Button = () =>
7 |
8 | const EnhancedButton = cssModules(Button, styles)
9 |
10 | ReactDOM.render(, document.body)
11 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "webpack-dev-server",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "eslint": "^2.9.0",
11 | "eslint-config-airbnb": "^9.0.1",
12 | "eslint-plugin-import": "^1.7.0",
13 | "eslint-plugin-jsx-a11y": "^1.2.0",
14 | "eslint-plugin-react": "^5.0.1",
15 | "babel-core": "^6.17.0",
16 | "babel-loader": "^6.2.5",
17 | "babel-preset-es2015": "^6.16.0",
18 | "babel-preset-react": "^6.16.0",
19 | "css-loader": "^0.25.0",
20 | "html-webpack-plugin": "^2.24.0",
21 | "style-loader": "^0.13.1",
22 | "webpack": "^1.13.2",
23 | "webpack-dev-server": "^1.16.2"
24 | },
25 | "dependencies": {
26 | "react": "^15.3.2",
27 | "react-css-modules": "^3.7.10",
28 | "react-dom": "^15.3.2"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/chapter-07/css-modules/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './index.js',
5 |
6 | module: {
7 | loaders: [
8 | {
9 | test: /\.js$/,
10 | exclude: /(node_modules|bower_components)/,
11 | loader: 'babel',
12 | query: {
13 | presets: ['es2015', 'react'],
14 | },
15 | },
16 | {
17 | test: /\.css$/,
18 | loader: 'style!css?modules&localIdentName=[local]--[hash:base64:5]',
19 | },
20 | ],
21 | },
22 |
23 | plugins: [new HtmlWebpackPlugin()],
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-07/inline-styles/favicon.ico
--------------------------------------------------------------------------------
/chapter-07/inline-styles/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import FontSize from './components/font-size'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/components/font-size.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class FontSize extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | value: 16,
10 | }
11 |
12 | this.handleChange = this.handleChange.bind(this)
13 | }
14 |
15 | handleChange({ target }) {
16 | this.setState({
17 | value: Number(target.value),
18 | })
19 | }
20 |
21 | render() {
22 | return (
23 |
29 | )
30 | }
31 |
32 | }
33 |
34 | export default FontSize
35 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-07/inline-styles/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-07/radium/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-07/radium/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-07/radium/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-07/radium/favicon.ico
--------------------------------------------------------------------------------
/chapter-07/radium/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-07/radium/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "radium": "^0.18.1",
15 | "react": "^15.3.1",
16 | "react-dom": "^15.3.1"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import { StyleRoot } from 'radium'
6 | import Button from './components/button'
7 |
8 | class App extends Component {
9 | render() {
10 | return (
11 |
12 |
13 |
14 |

15 |
Welcome to React
16 |
17 |
18 |
19 |
20 | )
21 | }
22 | }
23 |
24 | export default App
25 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/components/button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import radium from 'radium'
3 |
4 | const styles = {
5 | backgroundColor: '#ff0000',
6 | width: 320,
7 | padding: 20,
8 | borderRadius: 5,
9 | border: 'none',
10 | outline: 'none',
11 | ':hover': {
12 | color: '#fff',
13 | },
14 | ':active': {
15 | position: 'relative',
16 | top: 2,
17 | },
18 | '@media (max-width: 480px)': {
19 | width: 160,
20 | },
21 | }
22 |
23 | const Button = () =>
24 |
25 | export default radium(Button)
26 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-07/radium/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-07/styled-components/favicon.ico
--------------------------------------------------------------------------------
/chapter-07/styled-components/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1",
16 | "styled-components": "^1.0.8"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Button from './components/button'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/src/components/button.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | const Button = styled.button`
4 | background-color: #ff0000;
5 | width: 320px;
6 | padding: 20px;
7 | border-radius: 5px;
8 | border: none;
9 | outline: none;
10 | &:hover {
11 | color: #fff;
12 | }
13 | &:active {
14 | position: relative;
15 | top: 2px;
16 | }
17 | @media (max-width: 480px) {
18 | width: 160px;
19 | }`
20 |
21 | export default Button
22 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-07/styled-components/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "webpack",
7 | "start": "node ./dist/server",
8 | "lint": "eslint ./src"
9 | },
10 | "devDependencies": {
11 | "babel-core": "^6.18.0",
12 | "babel-loader": "^6.2.6",
13 | "babel-preset-es2015": "^6.18.0",
14 | "babel-preset-react": "^6.16.0",
15 | "eslint": "^2.9.0",
16 | "eslint-config-airbnb": "^9.0.1",
17 | "eslint-plugin-import": "^1.7.0",
18 | "eslint-plugin-jsx-a11y": "^1.2.0",
19 | "eslint-plugin-react": "^5.0.1",
20 | "webpack": "^1.13.3",
21 | "webpack-node-externals": "^1.5.4"
22 | },
23 | "dependencies": {
24 | "express": "^4.14.0",
25 | "isomorphic-fetch": "^2.2.1",
26 | "react": "^15.3.2",
27 | "react-dom": "^15.3.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/src/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const App = ({ gists }) => (
4 |
5 | {gists.map(gist => (
6 | - {gist.description}
7 | ))}
8 |
9 | )
10 |
11 | App.propTypes = {
12 | gists: React.PropTypes.array,
13 | }
14 |
15 | export default App
16 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/src/client.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './app'
4 |
5 | ReactDOM.render(, document.getElementById('app'))
6 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/src/server.js:
--------------------------------------------------------------------------------
1 | import express from 'express'
2 | import React from 'react'
3 | import ReactDOM from 'react-dom/server'
4 | import fetch from 'isomorphic-fetch'
5 | import App from './app'
6 | import template from './template'
7 |
8 | const app = express()
9 |
10 | app.use(express.static('dist/public'))
11 |
12 | app.get('/', (req, res) => {
13 | fetch('https://api.github.com/users/gaearon/gists')
14 | .then(response => response.json())
15 | .then(gists => {
16 | const body = ReactDOM.renderToString()
17 | const html = template(body, gists)
18 |
19 | res.send(html)
20 | })
21 | })
22 |
23 | app.listen(3000, () => {
24 | console.log('Listening on port 3000')
25 | })
26 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/src/template.js:
--------------------------------------------------------------------------------
1 | export default (body, gists) => `
2 |
3 |
4 |
5 |
6 |
7 |
8 | ${body}
9 |
10 |
11 |
12 |
13 | `
14 |
--------------------------------------------------------------------------------
/chapter-08/data-fetching/webpack.config.js:
--------------------------------------------------------------------------------
1 | const nodeExternals = require('webpack-node-externals')
2 |
3 | const loaders = [{
4 | test: /\.js$/,
5 | exclude: /(node_modules|bower_components)/,
6 | loader: 'babel',
7 | query: {
8 | presets: ['es2015', 'react'],
9 | },
10 | }]
11 |
12 | const client = {
13 | entry: './src/client.js',
14 |
15 | output: {
16 | path: './dist/public',
17 | filename: 'bundle.js',
18 | },
19 |
20 | module: { loaders },
21 | }
22 |
23 | const server = {
24 | entry: './src/server.js',
25 |
26 | output: {
27 | path: './dist',
28 | filename: 'server.js',
29 | },
30 |
31 | module: { loaders },
32 |
33 | target: 'node',
34 |
35 | externals: [nodeExternals()],
36 | }
37 |
38 | module.exports = [client, server]
39 |
--------------------------------------------------------------------------------
/chapter-08/next/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "parserOptions": {
5 | "ecmaVersion": 8
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/chapter-08/next/.gitignore:
--------------------------------------------------------------------------------
1 | .next
2 | node_modules
3 |
--------------------------------------------------------------------------------
/chapter-08/next/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next",
7 | "lint": "eslint ./pages"
8 | },
9 | "devDependencies": {
10 | "eslint": "^2.9.0",
11 | "eslint-config-airbnb": "^9.0.1",
12 | "eslint-plugin-import": "^1.7.0",
13 | "eslint-plugin-jsx-a11y": "^1.2.0",
14 | "eslint-plugin-react": "^5.0.1"
15 | },
16 | "dependencies": {
17 | "isomorphic-fetch": "^2.2.1",
18 | "next": "^1.0.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/chapter-08/next/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import fetch from 'isomorphic-fetch'
3 |
4 | class App extends React.Component {
5 |
6 | static async getInitialProps() {
7 | const response = await fetch('https://api.github.com/users/gaearon/gists')
8 | const gists = await response.json()
9 |
10 | return { gists }
11 | }
12 |
13 | render() {
14 | return (
15 |
16 | {this.props.gists.map(gist => (
17 | - {gist.description}
18 | ))}
19 |
20 | )
21 | }
22 |
23 | }
24 |
25 | App.propTypes = {
26 | gists: React.PropTypes.array,
27 | }
28 |
29 | export default App
30 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "webpack",
7 | "start": "node ./dist/server",
8 | "lint": "eslint ./src"
9 | },
10 | "devDependencies": {
11 | "babel-core": "^6.18.0",
12 | "babel-loader": "^6.2.6",
13 | "babel-preset-es2015": "^6.18.0",
14 | "babel-preset-react": "^6.16.0",
15 | "eslint": "^2.9.0",
16 | "eslint-config-airbnb": "^9.0.1",
17 | "eslint-plugin-import": "^1.7.0",
18 | "eslint-plugin-jsx-a11y": "^1.2.0",
19 | "eslint-plugin-react": "^5.0.1",
20 | "webpack": "^1.13.3",
21 | "webpack-node-externals": "^1.5.4"
22 | },
23 | "dependencies": {
24 | "express": "^4.14.0",
25 | "react": "^15.3.2",
26 | "react-dom": "^15.3.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/src/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const App = () => Hello React
4 |
5 | export default App
6 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/src/client.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './app'
4 |
5 | ReactDOM.render(, document.getElementById('app'))
6 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/src/server.js:
--------------------------------------------------------------------------------
1 | import express from 'express'
2 | import React from 'react'
3 | import ReactDOM from 'react-dom/server'
4 | import App from './app'
5 | import template from './template'
6 |
7 | const app = express()
8 |
9 | app.use(express.static('dist/public'))
10 |
11 | app.get('/', (req, res) => {
12 | const body = ReactDOM.renderToString()
13 | const html = template(body)
14 | res.send(html)
15 | })
16 |
17 | app.listen(3000, () => {
18 | console.log('Listening on port 3000')
19 | })
20 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/src/template.js:
--------------------------------------------------------------------------------
1 | export default body => `
2 |
3 |
4 |
5 |
6 |
7 |
8 | ${body}
9 |
10 |
11 |
12 | `
13 |
--------------------------------------------------------------------------------
/chapter-08/server-side-rendering/webpack.config.js:
--------------------------------------------------------------------------------
1 | const nodeExternals = require('webpack-node-externals')
2 |
3 | const loaders = [{
4 | test: /\.js$/,
5 | exclude: /(node_modules|bower_components)/,
6 | loader: 'babel',
7 | query: {
8 | presets: ['es2015', 'react'],
9 | },
10 | }]
11 |
12 | const client = {
13 | entry: './src/client.js',
14 |
15 | output: {
16 | path: './dist/public',
17 | filename: 'bundle.js',
18 | },
19 |
20 | module: { loaders },
21 | }
22 |
23 | const server = {
24 | entry: './src/server.js',
25 |
26 | output: {
27 | path: './dist',
28 | filename: 'server.js',
29 | },
30 |
31 | module: { loaders },
32 |
33 | target: 'node',
34 |
35 | externals: [nodeExternals()],
36 | }
37 |
38 | module.exports = [client, server]
39 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "global-require": 0,
7 | "react/prefer-stateless-function": 0
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-09/constants-props/favicon.ico
--------------------------------------------------------------------------------
/chapter-09/constants-props/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-addons-perf": "^15.3.2",
12 | "react-scripts": "0.2.2",
13 | "why-did-you-update": "0.0.8"
14 | },
15 | "dependencies": {
16 | "react": "^15.3.1",
17 | "react-dom": "^15.3.1"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "eject": "react-scripts eject",
23 | "lint": "eslint ./src"
24 | },
25 | "eslintConfig": {
26 | "extends": "./node_modules/react-scripts/config/eslint.js"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | if (process.env.NODE_ENV !== 'production') {
6 | const { whyDidYouUpdate } = require('why-did-you-update')
7 | whyDidYouUpdate(React)
8 | }
9 |
10 | import List from './components/list'
11 |
12 | class App extends Component {
13 | render() {
14 | return (
15 |
16 |
17 |

18 |
Welcome to React
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/components/item.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Item extends React.PureComponent {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.handleClick = this.handleClick.bind(this)
9 | }
10 |
11 | handleClick() {
12 | this.props.onClick(this.props.item)
13 | }
14 |
15 | render() {
16 | return (
17 |
18 | {this.props.item}
19 |
20 | )
21 | }
22 |
23 | }
24 |
25 | export default Item
26 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Perf from 'react-addons-perf'
3 | import Item from './item'
4 |
5 | const statuses = ['open', 'close']
6 |
7 | class List extends React.Component {
8 |
9 | constructor(props) {
10 | super(props)
11 |
12 | this.state = {
13 | items: ['foo', 'bar'],
14 | }
15 |
16 | this.handleClick = this.handleClick.bind(this)
17 | }
18 |
19 | componentWillUpdate() {
20 | Perf.start()
21 | }
22 |
23 | componentDidUpdate() {
24 | Perf.stop()
25 | Perf.printWasted()
26 | }
27 |
28 | handleClick() {
29 | const items = this.state.items.slice()
30 | items.unshift('baz')
31 |
32 | this.setState({
33 | items,
34 | })
35 | }
36 |
37 | render() {
38 | return (
39 |
40 |
41 | {this.state.items.map(item => (
42 |
48 | ))}
49 |
50 |
51 |
52 | )
53 | }
54 |
55 | }
56 |
57 | export default List
58 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-09/constants-props/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "global-require": 0,
7 | "react/prefer-stateless-function": 0
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-09/creating-functions/favicon.ico
--------------------------------------------------------------------------------
/chapter-09/creating-functions/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-addons-perf": "^15.3.2",
12 | "react-scripts": "0.2.2",
13 | "why-did-you-update": "0.0.8"
14 | },
15 | "dependencies": {
16 | "react": "^15.3.1",
17 | "react-dom": "^15.3.1"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "eject": "react-scripts eject",
23 | "lint": "eslint ./src"
24 | },
25 | "eslintConfig": {
26 | "extends": "./node_modules/react-scripts/config/eslint.js"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | if (process.env.NODE_ENV !== 'production') {
6 | const { whyDidYouUpdate } = require('why-did-you-update')
7 | whyDidYouUpdate(React)
8 | }
9 |
10 | import List from './components/list'
11 |
12 | class App extends Component {
13 | render() {
14 | return (
15 |
16 |
17 |

18 |
Welcome to React
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/components/item.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Item extends React.PureComponent {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.handleClick = this.handleClick.bind(this)
9 | }
10 |
11 | handleClick() {
12 | this.props.onClick(this.props.item)
13 | }
14 |
15 | render() {
16 | return (
17 |
18 | {this.props.item}
19 |
20 | )
21 | }
22 |
23 | }
24 |
25 | export default Item
26 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Perf from 'react-addons-perf'
3 | import Item from './item'
4 |
5 | class List extends React.Component {
6 |
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = {
11 | items: ['foo', 'bar'],
12 | }
13 |
14 | this.handleClick = this.handleClick.bind(this)
15 | }
16 |
17 | componentWillUpdate() {
18 | Perf.start()
19 | }
20 |
21 | componentDidUpdate() {
22 | Perf.stop()
23 | Perf.printWasted()
24 | }
25 |
26 | handleClick() {
27 | const items = this.state.items.slice()
28 | items.unshift('baz')
29 |
30 | this.setState({
31 | items,
32 | })
33 | }
34 |
35 | render() {
36 | return (
37 |
38 |
39 | {this.state.items.map(item => (
40 |
41 | ))}
42 |
43 |
44 |
45 | )
46 | }
47 |
48 | }
49 |
50 | export default List
51 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-09/creating-functions/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-09/good-design/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-09/good-design/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-09/good-design/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-09/good-design/favicon.ico
--------------------------------------------------------------------------------
/chapter-09/good-design/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/good-design/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Todos from './components/todos'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/components/form.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Form extends React.PureComponent {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | value: '',
10 | }
11 |
12 | this.handleChange = this.handleChange.bind(this)
13 | }
14 |
15 | handleChange({ target }) {
16 | this.setState({
17 | value: target.value,
18 | })
19 | }
20 |
21 | render() {
22 | return (
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
30 | }
31 |
32 | export default Form
33 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class List extends React.PureComponent {
4 |
5 | render() {
6 | return (
7 |
8 | {this.props.items.map(item => - {item}
)}
9 |
10 | )
11 | }
12 |
13 | }
14 |
15 | export default List
16 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/components/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import List from './list'
3 | import Form from './form'
4 |
5 | class Todos extends React.Component {
6 |
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = {
11 | items: ['foo', 'bar'],
12 | }
13 |
14 | this.handleSubmit = this.handleSubmit.bind(this)
15 | }
16 |
17 | handleSubmit(value) {
18 | const items = this.state.items.slice()
19 | items.unshift(value)
20 |
21 | this.setState({
22 | items,
23 | })
24 | }
25 |
26 | render() {
27 | return (
28 |
29 |
30 |
31 |
32 | )
33 | }
34 | }
35 |
36 | export default Todos
37 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-09/good-design/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-09/keys/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-09/keys/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-09/keys/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-09/keys/favicon.ico
--------------------------------------------------------------------------------
/chapter-09/keys/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/keys/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-addons-perf": "^15.3.2",
12 | "react-scripts": "0.2.2"
13 | },
14 | "dependencies": {
15 | "react": "^15.3.1",
16 | "react-dom": "^15.3.1"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import List from './components/list'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Perf from 'react-addons-perf'
3 |
4 | class List extends React.Component {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.state = {
10 | items: ['foo', 'bar'],
11 | }
12 |
13 | this.handleClick = this.handleClick.bind(this)
14 | }
15 |
16 | componentWillUpdate() {
17 | Perf.start()
18 | }
19 |
20 | componentDidUpdate() {
21 | Perf.stop()
22 | Perf.printOperations()
23 | }
24 |
25 | handleClick() {
26 | const items = this.state.items.slice()
27 | items.unshift('baz')
28 |
29 | this.setState({
30 | items,
31 | })
32 | }
33 |
34 | render() {
35 | return (
36 |
37 |
38 | {this.state.items.map(item => - {item}
)}
39 |
40 |
41 |
42 | )
43 | }
44 |
45 | }
46 |
47 | export default List
48 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-09/keys/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "env": {
5 | "jest": true
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"],
10 | "react/prefer-stateless-function": 0
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Button extends React.Component {
4 |
5 | render() {
6 | return (
7 |
10 | )
11 | }
12 |
13 | }
14 |
15 | Button.propTypes = {
16 | onClick: React.PropTypes.func,
17 | text: React.PropTypes.string,
18 | }
19 |
20 | export default Button
21 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/button.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { shallow } from 'enzyme'
3 | import Button from './button'
4 |
5 | test('renders with text', () => {
6 | const text = 'text'
7 | const button = shallow()
8 |
9 | expect(button.type()).toBe('button')
10 | expect(button.text()).toBe(text)
11 | })
12 |
13 | test('fires the onClick callback', () => {
14 | const onClick = jest.fn()
15 | const button = shallow()
16 |
17 | button.simulate('click')
18 |
19 | expect(onClick).toBeCalled()
20 | })
21 |
--------------------------------------------------------------------------------
/chapter-10/enzyme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "babel-jest": "^17.0.0",
11 | "babel-preset-es2015": "^6.18.0",
12 | "babel-preset-react": "^6.16.0",
13 | "enzyme": "^2.6.0",
14 | "eslint": "^2.9.0",
15 | "eslint-config-airbnb": "^9.0.1",
16 | "eslint-plugin-import": "^1.7.0",
17 | "eslint-plugin-jsx-a11y": "^1.2.0",
18 | "eslint-plugin-react": "^5.0.1",
19 | "jest": "^17.0.0",
20 | "react-addons-test-utils": "^15.3.2"
21 | },
22 | "dependencies": {
23 | "react": "^15.3.2",
24 | "react-dom": "^15.3.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "env": {
5 | "jest": true
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/__snapshots__/list.spec.js.snap:
--------------------------------------------------------------------------------
1 | exports[`test shows the gists 1`] = `
2 |
3 | -
4 | description
5 |
6 |
7 | `;
8 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/get-json.js:
--------------------------------------------------------------------------------
1 | export default endpoint => fetch(endpoint).then(response => response.json())
2 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const List = ({ data: gists }) => (
4 |
5 | {gists.map(gist => (
6 | - {gist.description}
7 | ))}
8 |
9 | )
10 |
11 | List.propTypes = {
12 | data: React.PropTypes.array,
13 | }
14 |
15 | export default List
16 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/list.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import renderer from 'react-test-renderer'
3 | import List from './list'
4 |
5 | test('shows the gists', () => {
6 | const gists = [{ id: 1, description: 'description' }]
7 | const component = renderer.create(
)
8 | const tree = component.toJSON()
9 |
10 | expect(tree).toMatchSnapshot()
11 | })
12 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "babel-jest": "^17.0.0",
11 | "babel-preset-es2015": "^6.18.0",
12 | "babel-preset-react": "^6.16.0",
13 | "enzyme": "^2.6.0",
14 | "eslint": "^2.9.0",
15 | "eslint-config-airbnb": "^9.0.1",
16 | "eslint-plugin-import": "^1.7.0",
17 | "eslint-plugin-jsx-a11y": "^1.2.0",
18 | "eslint-plugin-react": "^5.0.1",
19 | "jest": "^17.0.0",
20 | "react-addons-test-utils": "^15.3.2",
21 | "react-test-renderer": "^15.3.2"
22 | },
23 | "dependencies": {
24 | "react": "^15.3.2",
25 | "react-dom": "^15.3.2"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/with-data.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import getJSON from './get-json'
3 |
4 | const withData = url => Component => (
5 | class extends React.Component {
6 |
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = { data: [] }
11 | }
12 |
13 | componentDidMount() {
14 | const endpoint = typeof url === 'function' ? url(this.props) : url
15 |
16 | getJSON(endpoint).then(data => this.setState({ data }))
17 | }
18 |
19 | render() {
20 | return
21 | }
22 |
23 | }
24 | )
25 |
26 | export default withData
27 |
--------------------------------------------------------------------------------
/chapter-10/higher-order-components/with-data.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { shallow, mount } from 'enzyme'
3 | import withData from './with-data'
4 | import getJSON from './get-json'
5 |
6 | const data = 'data'
7 | const List = () =>
8 |
9 | jest.mock('./get-json', () => (
10 | jest.fn(() => ({ then: callback => callback(data) }))
11 | ))
12 |
13 | test('passes the props to the component', () => {
14 | const ListWithGists = withData()(List)
15 | const username = 'gaearon'
16 |
17 | const wrapper = shallow()
18 |
19 | expect(wrapper.prop('username')).toBe(username)
20 | })
21 |
22 | test('uses the string url', () => {
23 | const url = 'https://api.github.com/users/gaearon/gists'
24 | const withGists = withData(url)
25 | const ListWithGists = withGists(List)
26 |
27 | mount()
28 |
29 | expect(getJSON).toHaveBeenCalledWith(url)
30 | })
31 |
32 | test('uses the function url', () => {
33 | const url = jest.fn(props => `https://api.github.com/users/${props.username}/gists`)
34 | const withGists = withData(url)
35 | const ListWithGists = withGists(List)
36 | const props = { username: 'gaearon' }
37 |
38 | mount()
39 |
40 | expect(url).toHaveBeenCalledWith(props)
41 | expect(getJSON).toHaveBeenCalledWith('https://api.github.com/users/gaearon/gists')
42 | })
43 |
44 | test('passes the data to the component', () => {
45 | const ListWithGists = withData()(List)
46 |
47 | const wrapper = mount()
48 |
49 | expect(wrapper.find(List).prop('data')).toEqual(data)
50 | })
51 |
--------------------------------------------------------------------------------
/chapter-10/jest/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/chapter-10/jest/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "env": {
5 | "jest": true
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"],
10 | "react/prefer-stateless-function": 0
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-10/jest/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-10/jest/button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Button extends React.Component {
4 |
5 | render() {
6 | return (
7 |
10 | )
11 | }
12 |
13 | }
14 |
15 | Button.propTypes = {
16 | onClick: React.PropTypes.func,
17 | text: React.PropTypes.string,
18 | }
19 |
20 | export default Button
21 |
--------------------------------------------------------------------------------
/chapter-10/jest/button.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import TestUtils from 'react-addons-test-utils'
3 | import Button from './button'
4 |
5 | test('renders with text', () => {
6 | const text = 'text'
7 |
8 | const renderer = TestUtils.createRenderer()
9 | renderer.render()
10 | const button = renderer.getRenderOutput()
11 |
12 | expect(button.type).toBe('button')
13 | expect(button.props.children).toBe(text)
14 | })
15 |
16 | test('fires the onClick callback', () => {
17 | const onClick = jest.fn()
18 |
19 | const tree = TestUtils.renderIntoDocument()
20 | const button = TestUtils.findRenderedDOMComponentWithTag(tree, 'button')
21 |
22 | TestUtils.Simulate.click(button)
23 |
24 | expect(onClick).toBeCalled()
25 | })
26 |
--------------------------------------------------------------------------------
/chapter-10/jest/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "babel-jest": "^17.0.0",
11 | "babel-preset-es2015": "^6.18.0",
12 | "babel-preset-react": "^6.16.0",
13 | "eslint": "^2.9.0",
14 | "eslint-config-airbnb": "^9.0.1",
15 | "eslint-plugin-import": "^1.7.0",
16 | "eslint-plugin-jsx-a11y": "^1.2.0",
17 | "eslint-plugin-react": "^5.0.1",
18 | "jest": "^17.0.0",
19 | "react-addons-test-utils": "^15.3.2"
20 | },
21 | "dependencies": {
22 | "react": "^15.3.2",
23 | "react-dom": "^15.3.2"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/chapter-10/mocha/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/chapter-10/mocha/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "env": {
5 | "mocha": true
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"],
10 | "react/prefer-stateless-function": 0
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-10/mocha/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-10/mocha/button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Button extends React.Component {
4 |
5 | render() {
6 | return (
7 |
10 | )
11 | }
12 |
13 | }
14 |
15 | Button.propTypes = {
16 | onClick: React.PropTypes.func,
17 | text: React.PropTypes.string,
18 | }
19 |
20 | export default Button
21 |
--------------------------------------------------------------------------------
/chapter-10/mocha/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "mocha --compilers js:babel-register",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "babel-preset-es2015": "^6.18.0",
11 | "babel-preset-react": "^6.16.0",
12 | "babel-register": "^6.18.0",
13 | "chai": "^3.5.0",
14 | "chai-spies": "^0.7.1",
15 | "eslint": "^2.9.0",
16 | "eslint-config-airbnb": "^9.0.1",
17 | "eslint-plugin-import": "^1.7.0",
18 | "eslint-plugin-jsx-a11y": "^1.2.0",
19 | "eslint-plugin-react": "^5.0.1",
20 | "jsdom": "^9.8.3",
21 | "mocha": "^3.1.2",
22 | "react-addons-test-utils": "^15.3.2",
23 | "sinon": "^1.17.6"
24 | },
25 | "dependencies": {
26 | "react": "^15.3.2",
27 | "react-dom": "^15.3.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/chapter-10/mocha/test/button.spec.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai'
2 | import spies from 'chai-spies'
3 | import { jsdom } from 'jsdom'
4 | import React from 'react'
5 | import TestUtils from 'react-addons-test-utils'
6 | import Button from '../button'
7 |
8 | chai.use(spies)
9 |
10 | const { expect, spy } = chai
11 |
12 | global.document = jsdom('')
13 | global.window = document.defaultView
14 |
15 | describe('Button', () => {
16 | it('renders with text', () => {
17 | const text = 'text'
18 |
19 | const renderer = TestUtils.createRenderer()
20 | renderer.render()
21 | const button = renderer.getRenderOutput()
22 |
23 | expect(button.type).to.equal('button')
24 | expect(button.props.children).to.equal(text)
25 | })
26 |
27 | it('fires the onClick callback', () => {
28 | const onClick = spy()
29 |
30 | const tree = TestUtils.renderIntoDocument()
31 | const button = TestUtils.findRenderedDOMComponentWithTag(tree, 'button')
32 |
33 | TestUtils.Simulate.click(button)
34 |
35 | expect(onClick).to.be.called()
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/chapter-10/page-object/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/chapter-10/page-object/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "env": {
5 | "jest": true
6 | },
7 |
8 | "rules": {
9 | "semi": [2, "never"]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/chapter-10/page-object/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/chapter-10/page-object/form.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Controlled extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | firstName: 'Dan',
10 | lastName: 'Abramov',
11 | }
12 |
13 | this.handleChange = this.handleChange.bind(this)
14 | this.handleSubmit = this.handleSubmit.bind(this)
15 | }
16 |
17 | handleChange({ target }) {
18 | this.setState({
19 | [target.name]: target.value,
20 | })
21 | }
22 |
23 | handleSubmit(e) {
24 | e.preventDefault()
25 |
26 | this.props.onSubmit(`${this.state.firstName} ${this.state.lastName}`)
27 | }
28 |
29 | render() {
30 | return (
31 |
46 | )
47 | }
48 |
49 | }
50 |
51 | Controlled.propTypes = {
52 | onSubmit: React.PropTypes.func,
53 | }
54 |
55 | export default Controlled
56 |
--------------------------------------------------------------------------------
/chapter-10/page-object/form.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { shallow } from 'enzyme'
3 | import Controlled from './form'
4 | import Page from './page'
5 |
6 | test('submits the form', () => {
7 | const onSubmit = jest.fn()
8 | const wrapper = shallow()
9 |
10 | const firstName = wrapper.find('[name="firstName"]')
11 | firstName.simulate('change', { target: { name: 'firstName', value: 'Christopher' } })
12 |
13 | const lastName = wrapper.find('[name="lastName"]')
14 | lastName.simulate('change', { target: { name: 'lastName', value: 'Chedeau' } })
15 |
16 | const form = wrapper.find('form')
17 | form.simulate('submit', { preventDefault: () => {} })
18 |
19 | expect(onSubmit).toHaveBeenCalledWith('Christopher Chedeau')
20 | })
21 |
22 | test('submits the form with the page object', () => {
23 | const onSubmit = jest.fn()
24 | const wrapper = shallow()
25 |
26 | const page = new Page(wrapper)
27 | page.fill('firstName', 'Christopher')
28 | page.fill('lastName', 'Chedeau')
29 | page.submit()
30 |
31 | expect(onSubmit).toHaveBeenCalledWith('Christopher Chedeau')
32 | })
33 |
--------------------------------------------------------------------------------
/chapter-10/page-object/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest",
7 | "lint": "eslint ./"
8 | },
9 | "devDependencies": {
10 | "babel-jest": "^17.0.0",
11 | "babel-preset-es2015": "^6.18.0",
12 | "babel-preset-react": "^6.16.0",
13 | "enzyme": "^2.6.0",
14 | "eslint": "^2.9.0",
15 | "eslint-config-airbnb": "^9.0.1",
16 | "eslint-plugin-import": "^1.7.0",
17 | "eslint-plugin-jsx-a11y": "^1.2.0",
18 | "eslint-plugin-react": "^5.0.1",
19 | "jest": "^17.0.0",
20 | "react-addons-test-utils": "^15.3.2"
21 | },
22 | "dependencies": {
23 | "react": "^15.3.2",
24 | "react-dom": "^15.3.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-10/page-object/page.js:
--------------------------------------------------------------------------------
1 | class Page {
2 |
3 | constructor(wrapper) {
4 | this.wrapper = wrapper
5 | }
6 |
7 | fill(name, value) {
8 | const field = this.wrapper.find(`[name="${name}"]`)
9 | field.simulate('change', { target: { name, value } })
10 | }
11 |
12 | submit() {
13 | const form = this.wrapper.find('form')
14 | form.simulate('submit', { preventDefault() {} })
15 | }
16 |
17 | }
18 |
19 | export default Page
20 |
--------------------------------------------------------------------------------
/chapter-10/real-world/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"],
3 |
4 | "plugins": ["transform-class-properties"]
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-10/real-world/.gitignore:
--------------------------------------------------------------------------------
1 | coverage
2 | node_modules
3 |
--------------------------------------------------------------------------------
/chapter-10/real-world/TodoTextInput-snapshot.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import renderer from 'react-test-renderer'
3 | import TodoTextInput from './TodoTextInput'
4 |
5 | test('snapshots are awesome', () => {
6 | const component = renderer.create( {}} />)
7 | const tree = component.toJSON()
8 |
9 | expect(tree).toMatchSnapshot()
10 | })
11 |
--------------------------------------------------------------------------------
/chapter-10/real-world/TodoTextInput.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react'
2 | import classnames from 'classnames'
3 |
4 | export default class TodoTextInput extends Component {
5 | static propTypes = {
6 | onSave: PropTypes.func.isRequired,
7 | text: PropTypes.string,
8 | placeholder: PropTypes.string,
9 | editing: PropTypes.bool,
10 | newTodo: PropTypes.bool
11 | }
12 |
13 | state = {
14 | text: this.props.text || ''
15 | }
16 |
17 | handleSubmit = e => {
18 | const text = e.target.value.trim()
19 | if (e.which === 13) {
20 | this.props.onSave(text)
21 | if (this.props.newTodo) {
22 | this.setState({ text: '' })
23 | }
24 | }
25 | }
26 |
27 | handleChange = e => {
28 | this.setState({ text: e.target.value })
29 | }
30 |
31 | handleBlur = e => {
32 | if (!this.props.newTodo) {
33 | this.props.onSave(e.target.value)
34 | }
35 | }
36 |
37 | render() {
38 | return (
39 |
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/chapter-10/real-world/TodoTextInput.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { shallow } from 'enzyme'
3 | import TodoTextInput from './TodoTextInput'
4 |
5 | const noop = () => {}
6 |
7 | test('sets the text prop as value', () => {
8 | const text = 'text'
9 | const wrapper = shallow()
10 |
11 | expect(wrapper.prop('value')).toBe(text)
12 | })
13 |
14 | test('uses the placeholder prop', () => {
15 | const placeholder = 'placeholder'
16 | const wrapper = shallow()
17 |
18 | expect(wrapper.prop('placeholder')).toBe(placeholder)
19 | })
20 |
21 | test('applies the right class names', () => {
22 | const wrapper = shallow()
23 |
24 | expect(wrapper.hasClass('edit new-todo')).toBe(true)
25 | })
26 |
27 | test('fires onSave on enter', () => {
28 | const onSave = jest.fn()
29 | const value = 'value'
30 | const wrapper = shallow()
31 |
32 | wrapper.simulate('keydown', { target: { value }, which: 13 })
33 |
34 | expect(onSave).toHaveBeenCalledWith(value)
35 | })
36 |
37 | test('does not fire onSave on key down', () => {
38 | const onSave = jest.fn()
39 | const wrapper = shallow()
40 |
41 | wrapper.simulate('keydown', { target: { value: '' } })
42 |
43 | expect(onSave).not.toBeCalled()
44 | })
45 |
46 | test('clears the value after save if new', () => {
47 | const value = 'value'
48 | const wrapper = shallow()
49 |
50 | wrapper.simulate('keydown', { target: { value }, which: 13 })
51 |
52 | expect(wrapper.prop('value')).toBe('')
53 | })
54 |
55 | test('updates the text on change', () => {
56 | const value = 'value'
57 | const wrapper = shallow()
58 |
59 | wrapper.simulate('change', { target: { value } })
60 |
61 | expect(wrapper.prop('value')).toBe(value)
62 | })
63 |
64 | test('fires onSave on blur if not new', () => {
65 | const onSave = jest.fn()
66 | const value = 'value'
67 | const wrapper = shallow()
68 |
69 | wrapper.simulate('blur', { target: { value } })
70 |
71 | expect(onSave).toHaveBeenCalledWith(value)
72 | })
73 |
74 | test('does not fire onSave on blur if new', () => {
75 | const onSave = jest.fn()
76 | const wrapper = shallow()
77 |
78 | wrapper.simulate('blur')
79 |
80 | expect(onSave).not.toBeCalled()
81 | })
82 |
--------------------------------------------------------------------------------
/chapter-10/real-world/__snapshots__/TodoTextInput-snapshot.spec.js.snap:
--------------------------------------------------------------------------------
1 | exports[`test snapshots are awesome 1`] = `
2 |
11 | `;
12 |
--------------------------------------------------------------------------------
/chapter-10/real-world/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "test": "jest"
7 | },
8 | "jest": {
9 | "collectCoverage": true
10 | },
11 | "devDependencies": {
12 | "babel-jest": "^17.0.0",
13 | "babel-plugin-transform-class-properties": "^6.18.0",
14 | "babel-preset-es2015": "^6.18.0",
15 | "babel-preset-react": "^6.16.0",
16 | "enzyme": "^2.6.0",
17 | "jest": "^17.0.0",
18 | "react-addons-test-utils": "^15.3.2",
19 | "react-test-renderer": "^15.3.2"
20 | },
21 | "dependencies": {
22 | "classnames": "^2.2.5",
23 | "react": "^15.3.2",
24 | "react-dom": "^15.3.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-11/index-as-key/favicon.ico
--------------------------------------------------------------------------------
/chapter-11/index-as-key/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-addons-perf": "^15.3.2",
12 | "react-scripts": "0.2.2"
13 | },
14 | "dependencies": {
15 | "react": "^15.3.1",
16 | "react-dom": "^15.3.1"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "eject": "react-scripts eject",
22 | "lint": "eslint ./src"
23 | },
24 | "eslintConfig": {
25 | "extends": "./node_modules/react-scripts/config/eslint.js"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import List from './components/list'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Perf from 'react-addons-perf'
3 |
4 | class List extends React.PureComponent {
5 |
6 | constructor(props) {
7 | super(props)
8 |
9 | this.state = {
10 | items: ['foo', 'bar'],
11 | }
12 |
13 | this.handleClick = this.handleClick.bind(this)
14 | }
15 |
16 | componentWillUpdate() {
17 | Perf.start()
18 | }
19 |
20 | componentDidUpdate() {
21 | Perf.stop()
22 | Perf.printOperations()
23 | }
24 |
25 | handleClick() {
26 | const items = this.state.items.slice()
27 | items.unshift('baz')
28 |
29 | this.setState({
30 | items,
31 | })
32 | }
33 |
34 | render() {
35 | return (
36 |
47 | )
48 | }
49 |
50 | }
51 |
52 | export default List
53 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-11/index-as-key/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-11/initializing-state/favicon.ico
--------------------------------------------------------------------------------
/chapter-11/initializing-state/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Counter from './components/counter'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |

13 |
Welcome to React
14 |
15 |
16 |
17 | )
18 | }
19 | }
20 |
21 | export default App
22 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/src/components/counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Counter extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | count: props.initialCount,
10 | }
11 |
12 | this.handleClick = this.handleClick.bind(this)
13 | }
14 |
15 | handleClick() {
16 | this.setState({
17 | count: this.state.count + 1,
18 | })
19 | }
20 |
21 | render() {
22 | return (
23 |
24 | {this.state.count}
25 |
26 |
27 | )
28 | }
29 |
30 | }
31 |
32 | Counter.propTypes = {
33 | initialCount: React.PropTypes.number,
34 | }
35 |
36 | export default Counter
37 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-11/initializing-state/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "rules": {
5 | "semi": [2, "never"],
6 | "react/prefer-stateless-function": 0
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/chapter-11/mutating-state/favicon.ico
--------------------------------------------------------------------------------
/chapter-11/mutating-state/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-design-patterns-and-best-practices",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "eslint": "^2.9.0",
7 | "eslint-config-airbnb": "^9.0.1",
8 | "eslint-plugin-import": "^1.7.0",
9 | "eslint-plugin-jsx-a11y": "^1.2.0",
10 | "eslint-plugin-react": "^5.0.1",
11 | "react-scripts": "0.2.2"
12 | },
13 | "dependencies": {
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject",
21 | "lint": "eslint ./src"
22 | },
23 | "eslintConfig": {
24 | "extends": "./node_modules/react-scripts/config/eslint.js"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | margin-bottom: 20px;
16 | }
17 |
18 | @keyframes App-logo-spin {
19 | from { transform: rotate(0deg); }
20 | to { transform: rotate(360deg); }
21 | }
22 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from './logo.svg'
3 | import './App.css'
4 |
5 | import Counter from './components/counter'
6 | import List from './components/list'
7 |
8 | class App extends Component {
9 | render() {
10 | return (
11 |
12 |
13 |

14 |
Welcome to React
15 |
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | export default App
24 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/components/counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Counter extends React.Component {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | count: props.initialCount,
10 | }
11 |
12 | this.handleClick = this.handleClick.bind(this)
13 | }
14 |
15 | handleClick() {
16 | this.state.count++
17 | }
18 |
19 | render() {
20 | return (
21 |
22 | {this.state.count}
23 |
24 |
25 |
26 | )
27 | }
28 |
29 | }
30 |
31 | Counter.propTypes = {
32 | initialCount: React.PropTypes.number,
33 | }
34 |
35 | export default Counter
36 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/components/list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class List extends React.PureComponent {
4 |
5 | constructor(props) {
6 | super(props)
7 |
8 | this.state = {
9 | items: ['foo', 'bar'],
10 | }
11 |
12 | this.handleClick = this.handleClick.bind(this)
13 | }
14 |
15 | handleClick() {
16 | this.setState({
17 | items: this.state.items.concat('baz'),
18 | })
19 | }
20 |
21 | render() {
22 | return (
23 |
24 | {this.state.items.length}
25 |
26 |
27 | )
28 | }
29 |
30 | }
31 |
32 | export default List
33 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-11/mutating-state/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | )
10 |
--------------------------------------------------------------------------------
/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MicheleBertoli/react-design-patterns-and-best-practices/78fb849ff46a5b841ce4821f267b0ccfc67060ce/cover.jpg
--------------------------------------------------------------------------------