├── .eslintrc.json ├── .github ├── FUNDING.yml └── workflows │ ├── deploy.yml │ ├── firebase-hosting-merge.yml │ └── firebase-hosting-pull-request.yml ├── .gitignore ├── .storybook └── main.js ├── .travis.yml ├── .vscode └── launch.json ├── Mobile device.PNG ├── Performance.PNG ├── README.md ├── _config.yml ├── debug.log ├── email-module-2.gif ├── emailmodule.gif ├── firebase.json ├── music-player-module.gif ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── readme ├── DomElements.md ├── Hooks.md ├── REFERENCE-1.md ├── REFERENCE-2.md ├── REFERENCE-3.md ├── REFERENCE-4.md ├── React-Api.md ├── ReactComponent.md ├── ReactDom.md ├── ReactDomServer.md ├── Reconcillation.md ├── Ref-And-Dom.md ├── RenderProps.md ├── Shallow Renderer │ └── README.md ├── StrictMode.md ├── SyntheticEvent │ └── README.md ├── Test Utilities │ └── README.md ├── TypeCheckingWithProtoTypes.md ├── UnControlledComponent.md ├── hooks │ ├── README.md │ ├── api │ │ └── README.md │ ├── custom-hook │ │ └── README.md │ ├── rules │ │ └── README.md │ └── useState │ │ └── README.md ├── requirements │ └── README.md └── test renderer │ └── README.md ├── src ├── App.css ├── App.test.js ├── App.tsx ├── assets │ ├── hd.svg │ ├── image_loading_error.svg │ ├── loading.svg │ ├── mailbox.svg │ ├── night.svg │ ├── noon.svg │ └── sunny_day.svg ├── components │ ├── statefull │ │ ├── Email │ │ │ └── Email.tsx │ │ ├── TodoHome │ │ │ └── TodoHome.tsx │ │ ├── TodoImageList │ │ │ ├── TodoImageList.css │ │ │ └── TodoImageList.tsx │ │ └── TodoMusic │ │ │ └── TodoMusic.tsx │ └── stateless │ │ ├── Dialog │ │ ├── Dialog.css │ │ └── Dialog.tsx │ │ ├── EmailItems │ │ └── EmailItems.tsx │ │ ├── Greet │ │ ├── Greet.css │ │ └── Greet.tsx │ │ ├── ImageGridList │ │ ├── ImageGridList.css │ │ └── ImageGridList.tsx │ │ ├── ImageListPaging │ │ └── ImageListPaging.tsx │ │ ├── Login │ │ ├── Login.css │ │ └── Login.tsx │ │ ├── Logo │ │ ├── Logo.test.js │ │ └── Logo.tsx │ │ ├── Navigation │ │ ├── Navigation.css │ │ └── Navigation.tsx │ │ ├── NotificationSnackBar │ │ └── NotificationSnackbar.tsx │ │ ├── NowPlaying │ │ └── NowPlaying.tsx │ │ ├── PageNotFound │ │ ├── PageNotFound.css │ │ └── PageNotFound.tsx │ │ ├── RouterNavigation │ │ └── RouterNavigation.tsx │ │ ├── ShowEmail │ │ └── ShowEmail.tsx │ │ ├── ThemeWidget │ │ ├── ThemeWidget.css │ │ └── ThemeWidget.tsx │ │ ├── TodoAdd │ │ ├── TodoAdd.css │ │ └── TodoAdd.tsx │ │ ├── TodoListContainer │ │ ├── TodoListContainer.css │ │ └── TodoListContainer.tsx │ │ ├── TodoListItem │ │ ├── TodoListItem.css │ │ └── TodoListItem.tsx │ │ └── TodoMusicList │ │ └── TodoMusicList.tsx ├── context │ └── ThemeManager.ts ├── error-component │ └── ErrorComponent.tsx ├── index.css ├── index.tsx ├── interfaces │ ├── Actions.ts │ ├── App.ts │ ├── Dialog.ts │ ├── EmailAppState.ts │ ├── EmailItems.ts │ ├── Greet.ts │ ├── ImageListItem.ts │ ├── ImageLoaderInterface.ts │ ├── Logo.ts │ ├── MusicItem.ts │ ├── MusicResult.ts │ ├── NotificationSnackbar.ts │ ├── SliderInterface.ts │ ├── State.ts │ ├── Themes.ts │ ├── TodoHome.ts │ ├── TodoList.ts │ ├── TodoListItem.ts │ ├── login.interface.ts │ └── routeconfig..ts ├── list.svg ├── logo.svg ├── react-app-env.d.ts ├── serviceWorker.ts ├── shared │ ├── CustomSvg │ │ ├── CustomSvg.css │ │ └── CustomSvg.tsx │ ├── Drawer │ │ └── NavDrawer.tsx │ ├── ImageLoading.tsx │ ├── InfiniteScrolling │ │ └── InfiniteScollingContainer.tsx │ ├── Loader │ │ └── Loader.tsx │ └── PrettoSlider.tsx ├── store │ ├── actions │ │ ├── email.action.ts │ │ ├── login.action.ts │ │ ├── music.action.ts │ │ ├── notification.action.ts │ │ └── todo.action.ts │ ├── index.ts │ ├── reducers │ │ ├── email.reducer.ts │ │ ├── login.reducer.ts │ │ ├── music.reducer.ts │ │ ├── notification.reducer.ts │ │ └── todo.reducer.ts │ └── selectors │ │ ├── email.selector.ts │ │ ├── login.selector.ts │ │ ├── music.selector.ts │ │ ├── notification.selector.ts │ │ └── todo.selector.ts ├── stories │ ├── 0-Welcome.stories.js │ └── 1-Button.stories.js └── utils │ ├── core.util.spec.ts │ ├── core.utils.ts │ ├── http.util.ts │ ├── logger.util.ts │ └── routes.util.tsx ├── tsconfig.json ├── typings.d.ts └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["react-app", "plugin:jsx-a11y/recommended"] 3 | } 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [narendrasinghrathore] 4 | custom: ["https://paypal.me/frontendadvocate?locale.x=en_GB"] 5 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout Repo 13 | uses: actions/checkout@master 14 | - name: Install Dependencies 15 | run: npm install 16 | - name: Build 17 | run: npm run build 18 | - name: Archive Production Artifact 19 | uses: actions/upload-artifact@master 20 | with: 21 | name: build 22 | path: build 23 | deploy: 24 | name: Deploy 25 | needs: build 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout Repo 29 | uses: actions/checkout@master 30 | - name: Download Artifact 31 | uses: actions/download-artifact@master 32 | with: 33 | name: build 34 | path: build 35 | - name: Deploy to Firebase 36 | uses: w9jds/firebase-action@master 37 | with: 38 | args: deploy --only hosting 39 | env: 40 | FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | 'on': 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: npm i && npm run build 15 | - uses: FirebaseExtended/action-hosting-deploy@v0 16 | with: 17 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 18 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_APPTODOREACT }}' 19 | channelId: live 20 | projectId: apptodoreact 21 | env: 22 | FIREBASE_CLI_PREVIEWS: hostingchannels 23 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | 'on': pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: npm i && npm run build 12 | - uses: FirebaseExtended/action-hosting-deploy@v0 13 | with: 14 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 15 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_APPTODOREACT }}' 16 | projectId: apptodoreact 17 | env: 18 | FIREBASE_CLI_PREVIEWS: hostingchannels 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .firebaserc 25 | .firebase/hosting.YnVpbGQ.cache 26 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../src/**/*.stories.js'], 3 | addons: [ 4 | '@storybook/preset-create-react-app', 5 | '@storybook/addon-actions', 6 | '@storybook/addon-links', 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10.16.3" 4 | script: 5 | - echo "Deploy!!" 6 | - npm install 7 | - npm run build 8 | install: 9 | - npm install -g firebase-tools 10 | 11 | after_success: 12 | - firebase deploy --project apptodoreact --token $FIREBASE_TOKEN 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /Mobile device.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/Mobile device.PNG -------------------------------------------------------------------------------- /Performance.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/Performance.PNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Build Status](https://travis-ci.org/narendrasinghrathore/todo-app-react.svg?branch=master)](https://travis-ci.org/narendrasinghrathore/todo-app-react) 3 | 4 | ## Desktop Performance: 5 | 6 | 7 | 8 | 9 | ## Email module: 10 | 11 | 12 | 13 | 14 | ## Music Player module: 15 | 16 | 17 | 18 | 19 | 20 | 21 | ## Mobile View: 22 | 23 | 24 | 25 | ## Application covers: 26 | 27 | 1. Lazy loading components 28 | 2. Nested routing 29 | 3. Re-Usability of components 30 | 4. Stateful and Stateless component architecture 31 | 5. Async call using axios 32 | 6. Accessibility 33 | 7. Best practices 34 | 8. Performance 35 | 9. Suspense 36 | 10. React-Redux 37 | 11. Parameter based routing i.e. parameter and query based 38 | 12. React hooks i.e. useState and useEffect 39 | 13. Function based components using react hooks 40 | 14. Intersection Observer API 41 | 42 | ## Implementations 43 | This section contains the scenario we require and how we achieve them. 44 | 45 | 1. Dynamic background color in `` component, based on color selection from `` component 46 | 2. Snackbar notification using redux-store, ``. We can dispatch action that contains message, auto-hide in millisecond, status to show Snackbar. It can be used to display application related notification i.e success, error, warning etc. 47 | 3. If route not match, redirect to `` component. 48 | 4. Implementation of EMAIL module [here](https://apptodoreact.firebaseapp.com/email). It contains nested routing example using react-router-dom. Uses async call to update emails list in store (i.e. redux state management). 49 | 5. Using Intersection Observer API, we have implemented infinite scrolling feature in image module 50 | 51 | ## Available Scripts 52 | In the project directory, you can run: 53 | 54 | ### `npm start` 55 | 56 | Runs the app in the development mode.
57 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 58 | 59 | The page will reload if you make edits.
60 | 61 | You will also see any lint errors in the console. 62 | 63 | ### `npm test` 64 | Launches the test runner in the interactive watch mode.
65 | 66 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 67 | 68 | ### `npm run build` 69 | Builds the app for production to the `build` folder.
70 | It correctly bundles React in production mode and optimizes the build for the best performance. 71 | 72 | The build is minified and the filenames include the hashes.
73 | Your app is ready to be deployed! 74 | 75 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 76 | 77 | ### `npm run eject` 78 | 79 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 80 | 81 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 82 | 83 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 84 | 85 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 86 | 87 | ## Learn More 88 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 89 | 90 | To learn React, check out the [React documentation](https://reactjs.org/). 91 | 92 | ### Code Splitting 93 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 94 | ### Analyzing the Bundle Size 95 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 96 | ### Making a Progressive Web App 97 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 98 | ### Advanced Configuration 99 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 100 | ### Deployment 101 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 102 | ### `npm run build` fails to minify 103 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 104 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /debug.log: -------------------------------------------------------------------------------- 1 | [0124/102223.569:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 2 | [0206/104832.674:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 3 | [0207/074348.559:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 4 | [0208/074631.857:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 5 | [0213/133416.316:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 6 | [0213/181538.912:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 7 | [0217/134547.793:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 8 | [0218/110613.817:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 9 | [0218/155658.550:ERROR:registration_protocol_win.cc(84)] TransactNamedPipe: The pipe has been ended. (0x6D) 10 | -------------------------------------------------------------------------------- /email-module-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/email-module-2.gif -------------------------------------------------------------------------------- /emailmodule.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/emailmodule.gif -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /music-player-module.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/music-player-module.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-app-react", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.8.3", 7 | "@material-ui/icons": "^4.5.1", 8 | "@material-ui/lab": "^4.0.0-alpha.39", 9 | "@reduxjs/toolkit": "^1.2.1", 10 | "@types/node": "^13.1.6", 11 | "@types/react": "^16.9.17", 12 | "@types/react-dom": "^16.9.4", 13 | "@types/react-redux": "^7.1.5", 14 | "@types/react-router-dom": "^5.1.3", 15 | "@types/react-window": "^1.8.1", 16 | "@types/styled-components": "^4.4.2", 17 | "axios": "^0.21.1", 18 | "react": "^16.12.0", 19 | "react-dom": "^16.12.0", 20 | "react-redux": "^7.1.3", 21 | "react-router-dom": "^5.1.2", 22 | "react-scripts": "^4.0.3", 23 | "react-spring": "^8.0.27", 24 | "react-window": "^1.8.5", 25 | "redux": "^4.0.5", 26 | "redux-thunk": "^2.3.0", 27 | "source-map-explorer": "^2.2.2", 28 | "styled-components": "^4.4.1", 29 | "typescript": "^3.7.4" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test", 35 | "eject": "react-scripts eject", 36 | "analyze": "source-map-explorer 'build/static/js/*.js'", 37 | "storybook": "start-storybook -p 9009 -s public", 38 | "build-storybook": "build-storybook -s public" 39 | }, 40 | "eslintConfig": { 41 | "extends": "react-app" 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | }, 55 | "devDependencies": { 56 | "@babel/plugin-proposal-optional-chaining": "^7.8.0", 57 | "@storybook/addon-actions": "^5.3.13", 58 | "@storybook/addon-links": "^5.3.13", 59 | "@storybook/addons": "^5.3.13", 60 | "@storybook/preset-create-react-app": "^1.5.2", 61 | "@storybook/react": "^5.3.13", 62 | "eslint-plugin-react-hooks": "^2.3.0", 63 | "redux-devtools-extension": "^2.13.8" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/narendrasinghrathore/todo-app-react/dff208df6b8e99d7b65e36e2c4302faca4248629/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": "/login", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /readme/Hooks.md: -------------------------------------------------------------------------------- 1 | # Hooks 2 | _Hooks_ are a new addition in React 16.8. They let you use state and other React features without writing a class. 3 | 4 | 5 | import React, { useState } from 'react'; 6 | 7 | function Example() { 8 | // Declare a new state variable, which we'll call "count" 9 | const [count, setCount] = useState(0); 10 | 11 | return ( 12 |
13 |

You clicked {count} times

14 | 17 |
18 | ); 19 | } 20 | 21 | 22 | 23 | > **Note** 24 | > 25 | > React 16.8.0 is the first release to support Hooks. When upgrading, 26 | > don’t forget to update all packages, including React DOM. React Native 27 | > supports Hooks since [the 0.59 release of React 28 | > Native](https://facebook.github.io/react-native/blog/2019/03/12/releasing-react-native-059). 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /readme/REFERENCE-3.md: -------------------------------------------------------------------------------- 1 | # Optimizing Performance 2 | 3 | Internally, React uses several clever techniques to minimize the number of costly DOM operations required to update the UI. For many applications, using React will lead to a fast user interface without doing much work to specifically optimize for performance. Nevertheless, there are several ways you can speed up your React application. 4 | 5 | ## Use the Production Build 6 | If you’re benchmarking or experiencing performance problems in your React apps, make sure you’re testing with the minified production build. 7 | 8 | ## Brunch 9 | For the most efficient Brunch production build, install the terser-brunch plugin: 10 | 11 | # If you use npm 12 | npm install --save-dev terser-brunch 13 | 14 | # If you use Yarn 15 | yarn add --dev terser-brunch 16 | 17 | Then, to create a production build, add the -p flag to the build command: 18 | 19 | brunch build -p 20 | 21 | Remember that you only need to do this for production builds. You shouldn’t pass the -p flag or apply this plugin in development, because it will hide useful React warnings and make the builds much slower. 22 | 23 | ## Browserify 24 | For the most efficient Browserify production build, install a few plugins: 25 | 26 | # If you use npm 27 | npm install --save-dev envify terser uglifyify 28 | 29 | # If you use Yarn 30 | yarn add --dev envify terser uglifyify 31 | 32 | To create a production build, make sure that you add these transforms (the order matters): 33 | 34 | The envify transform ensures the right build environment is set. Make it global (-g). 35 | The uglifyify transform removes development imports. Make it global too (-g). 36 | Finally, the resulting bundle is piped to terser for mangling (read why) https://github.com/hughsk/uglifyify#motivationusage. 37 | 38 | 39 | For example: 40 | 41 | browserify ./index.js \ 42 | -g [ envify --NODE_ENV production ] \ 43 | -g uglifyify \ 44 | | terser --compress --mangle > ./bundle.js 45 | 46 | Remember that you only need to do this for production builds. You shouldn’t apply these plugins in development because they will hide useful React warnings, and make the builds much slower. 47 | 48 | ## Rollup 49 | For the most efficient Rollup production build, install a few plugins: 50 | 51 | #### If you use npm 52 | npm install --save-dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-terser 53 | 54 | #### If you use Yarn 55 | yarn add --dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-terser 56 | To create a production build, make sure that you add these plugins (the order matters): 57 | 58 | The replace plugin ensures the right build environment is set. 59 | The commonjs plugin provides support for CommonJS in Rollup. 60 | The terser plugin compresses and mangles the final bundle. 61 | 62 | plugins: [ 63 | // ... 64 | require('rollup-plugin-replace')({ 65 | 'process.env.NODE_ENV': JSON.stringify('production') 66 | }), 67 | require('rollup-plugin-commonjs')(), 68 | require('rollup-plugin-terser')(), 69 | // ... 70 | ] 71 | 72 | For a complete setup example see this gist https://gist.github.com/Rich-Harris/cb14f4bc0670c47d00d191565be36bf0. 73 | 74 | Remember that you only need to do this for production builds. You shouldn’t apply the terser plugin or the replace plugin with 'production' value in development because they will hide useful React warnings, and make the builds much slower. 75 | 76 | ## webpack 77 | 78 | Webpack v4+ will minify your code by default in production mode. 79 | 80 | const TerserPlugin = require('terser-webpack-plugin'); 81 | 82 | module.exports = { 83 | mode: 'production', 84 | optimization: { 85 | minimizer: [new TerserPlugin({ /* additional options here */ })], 86 | }, 87 | }; 88 | 89 | https://webpack.js.org/guides/production/ 90 | Remember that you only need to do this for production builds. You shouldn’t apply TerserPlugin in development because it will hide useful React warnings, and make the builds much slower. 91 | 92 | ## Profiling Components with the Chrome Performance Tab 93 | In the development mode, you can visualize how components mount, update, and unmount,using the performance tools in supported browsers. 94 | 95 | To do this in Chrome: 96 | 97 | Temporarily disable all Chrome extensions, especially React DevTools. They can significantly skew the results! 98 | 99 | Make sure you’re running the application in the development mode. 100 | 101 | Open the Chrome DevTools Performance tab and press Record. 102 | 103 | Perform the actions you want to profile. Don’t record more than 20 seconds or Chrome might hang. 104 | 105 | Stop recording. 106 | 107 | React events will be grouped under the User Timing label. 108 | 109 | Note that the numbers are relative so components will render faster in production. Still, this should help you realize when unrelated UI gets updated by mistake, and how deep and how often your UI updates occur. 110 | 111 | Currently Chrome, Edge, and IE are the only browsers supporting this feature, but we use the standard User Timing API https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API so we expect more browsers to add support for it. 112 | 113 | https://calibreapp.com/blog/2017-11-28-debugging-react/ 114 | 115 | 116 | 117 | ## Profiling Components with the DevTools Profiler 118 | react-dom 16.5+ and react-native 0.57+ provide enhanced profiling capabilities in DEV mode with the React DevTools Profiler. An overview of the Profiler can be found in the blog post “Introducing the React Profiler” https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html. A video walkthrough of the profiler is also available on YouTube https://www.youtube.com/watch?v=nySib7ipZdk. 119 | 120 | 121 | Note 122 | 123 | A production profiling bundle of react-dom is also available as react-dom/profiling. Read more about how to use this bundle at fb.me/react-profiling https://fb.me/react-profiling 124 | 125 | 126 | 127 | ## Virtualize Long Lists 128 | If your application renders long lists of data (hundreds or thousands of rows), we recommended using a technique known as “windowing”. This technique only renders a small subset of your rows at any given time, and can dramatically reduce the time it takes to re-render the components as well as the number of DOM nodes created. 129 | 130 | react-window https://react-window.now.sh/ and react-virtualized https://bvaughn.github.io/react-virtualized/ are popular windowing libraries. They provide several reusable components for displaying lists, grids, and tabular data. You can also create your own windowing component, like Twitter did https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3, if you want something more tailored to your application’s specific use case. 131 | 132 | ## Avoid Reconciliation 133 | React builds and maintains an internal representation of the rendered UI. It includes the React elements you return from your components. This representation lets React avoid creating DOM nodes and accessing existing ones beyond necessity, as that can be slower than operations on JavaScript objects. Sometimes it is referred to as a “virtual DOM”, but it works the same way on React Native. 134 | 135 | When a component’s props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one. When they are not equal, React will update the DOM. 136 | 137 | Even though React only updates the changed DOM nodes, re-rendering still takes some time. In many cases it’s not a problem, but if the slowdown is noticeable, you can speed all of this up by overriding the lifecycle function shouldComponentUpdate, which is triggered before the re-rendering process starts. The default implementation of this function returns true, leaving React to perform the update: 138 | 139 | shouldComponentUpdate(nextProps, nextState) { 140 | return true; 141 | } 142 | 143 | 144 | If you know that in some situations your component doesn’t need to update, you can return false from shouldComponentUpdate instead, to skip the whole rendering process, including calling render() on this component and below. 145 | 146 | In most cases, instead of writing shouldComponentUpdate() by hand, you can inherit from React.PureComponent https://reactjs.org/docs/react-api.html#reactpurecomponent. It is equivalent to implementing shouldComponentUpdate() with a shallow comparison of current and previous props and state. 147 | 148 | 149 | ## shouldComponentUpdate In Action 150 | Here’s a subtree of components. For each one, SCU indicates what shouldComponentUpdate returned, and vDOMEq indicates whether the rendered React elements were equivalent. Finally, the circle’s color indicates whether the component had to be reconciled or not. 151 | 152 | Please find example, how mutation degrade the performance https://reactjs.org/docs/optimizing-performance.html#examples -------------------------------------------------------------------------------- /readme/ReactDom.md: -------------------------------------------------------------------------------- 1 | # ReactDOM 2 | 3 | ## Overview 4 | 5 | The `react-dom` package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. Most of your components should not need to use this module. 6 | 7 | - [`render()`](https://reactjs.org/docs/react-dom.html#render) 8 | - [`hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) 9 | - [`unmountComponentAtNode()`](https://reactjs.org/docs/react-dom.html#unmountcomponentatnode) 10 | - [`findDOMNode()`](https://reactjs.org/docs/react-dom.html#finddomnode) 11 | - [`createPortal()`](https://reactjs.org/docs/react-dom.html#createportal) 12 | 13 | ### Browser Support 14 | 15 | React supports all popular browsers, including Internet Explorer 9 and above, although [some polyfills are required](https://reactjs.org/docs/javascript-environment-requirements.html) for older browsers such as IE 9 and IE 10. 16 | 17 | > Note 18 | > 19 | > We don’t support older browsers that don’t support ES5 methods, but you may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page. You’re on your own if you choose to take this path. 20 | 21 | 22 | ## Reference 23 | 24 | ### [](https://reactjs.org/docs/react-dom.html#render)`render()` 25 | 26 | ``` 27 | ReactDOM.render(element, container[, callback]) 28 | ``` 29 | 30 | Render a React element into the DOM in the supplied `container` and return a [reference](https://reactjs.org/docs/more-about-refs.html) to the component (or returns `null` for [stateless components](https://reactjs.org/docs/components-and-props.html#functional-and-class-components)). 31 | 32 | If the React element was previously rendered into `container`, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element. 33 | 34 | If the optional callback is provided, it will be executed after the component is rendered or updated. 35 | 36 | 37 | Note: 38 | 39 | `ReactDOM.render()` controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient updates. 40 | 41 | `ReactDOM.render()` does not modify the container node (only modifies the children of the container). It may be possible to insert a component to an existing DOM node without overwriting the existing children. 42 | 43 | `ReactDOM.render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root `ReactComponent` instance, the preferred solution is to attach a [callback ref](https://reactjs.org/docs/more-about-refs.html#the-ref-callback-attribute) to the root element. 44 | 45 | Using `ReactDOM.render()` to hydrate a server-rendered container is deprecated and will be removed in React 17. Use [`hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) instead. 46 | 47 | 48 | ### `hydrate()` 49 | 50 | ``` 51 | ReactDOM.hydrate(element, container[, callback]) 52 | ``` 53 | 54 | Same as [`render()`](https://reactjs.org/docs/react-dom.html#render), but is used to hydrate a container whose HTML contents were rendered by [`ReactDOMServer`](https://reactjs.org/docs/react-dom-server.html). React will attempt to attach event listeners to the existing markup. 55 | 56 | React expects that the rendered content is identical between the server and the client. It can patch up differences in text content, but you should treat mismatches as bugs and fix them. In development mode, React warns about mismatches during hydration. There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive. 57 | 58 | If a single element’s attribute or text content is unavoidably different between the server and the client (for example, a timestamp), you may silence the warning by adding `suppressHydrationWarning={true}` to the element. It only works one level deep, and is intended to be an escape hatch. Don’t overuse it. Unless it’s text content, React still won’t attempt to patch it up, so it may remain inconsistent until future updates. 59 | 60 | If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like `this.state.isClient`, which you can set to `true` in `componentDidMount()`. This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution. 61 | 62 | Remember to be mindful of user experience on slow connections. The JavaScript code may load significantly later than the initial HTML render, so if you render something different in the client-only pass, the transition can be jarring. However, if executed well, it may be beneficial to render a “shell” of the application on the server, and only show some of the extra widgets on the client. To learn how to do this without getting the markup mismatch issues, refer to the explanation in the previous paragraph. 63 | 64 | ---------- 65 | 66 | ### [`unmountComponentAtNode()`](https://reactjs.org/docs/react-dom.html#unmountcomponentatnode) 67 | 68 | ``` 69 | ReactDOM.unmountComponentAtNode(container) 70 | ``` 71 | 72 | Remove a mounted React component from the DOM and clean up its event handlers and state. If no component was mounted in the container, calling this function does nothing. Returns `true` if a component was unmounted and `false` if there was no component to unmount. 73 | 74 | ---------- 75 | 76 | ### [`findDOMNode()`](https://reactjs.org/docs/react-dom.html#finddomnode) 77 | 78 | > Note: 79 | > 80 | > `findDOMNode` is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction. [It has been deprecated in `StrictMode`.](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage) 81 | 82 | ``` 83 | ReactDOM.findDOMNode(component) 84 | ``` 85 | 86 | If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. **In most cases, you can attach a ref to the DOM node and avoid using `findDOMNode` at all.** 87 | 88 | When a component renders to `null` or `false`, `findDOMNode` returns `null`. When a component renders to a string, `findDOMNode` returns a text DOM node containing that value. As of React 16, a component may return a fragment with multiple children, in which case `findDOMNode` will return the DOM node corresponding to the first non-empty child. 89 | 90 | > Note: 91 | > 92 | > `findDOMNode` only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling `findDOMNode()` in `render()` on a component that has yet to be created) an exception will be thrown. 93 | > 94 | > `findDOMNode` cannot be used on function components. 95 | 96 | ---------- 97 | 98 | ### [`createPortal()`](https://reactjs.org/docs/react-dom.html#createportal) 99 | 100 | ``` 101 | ReactDOM.createPortal(child, container) 102 | ``` 103 | 104 | Creates a portal. Portals provide a way to [render children into a DOM node that exists outside the hierarchy of the DOM component](https://reactjs.org/docs/portals.html). 105 | 106 | -------------------------------------------------------------------------------- /readme/ReactDomServer.md: -------------------------------------------------------------------------------- 1 | # ReactDOMServer 2 | 3 | The `ReactDOMServer` object enables you to render components to static markup. Typically, it’s used on a Node server: 4 | 5 | ``` 6 | // ES modules 7 | import ReactDOMServer from 'react-dom/server'; 8 | // CommonJS 9 | var ReactDOMServer = require('react-dom/server'); 10 | ``` 11 | 12 | ## [Overview](https://reactjs.org/docs/react-dom-server.html#overview) 13 | 14 | The following methods can be used in both the server and browser environments: 15 | 16 | - [`renderToString()`](https://reactjs.org/docs/react-dom-server.html#rendertostring) 17 | - [`renderToStaticMarkup()`](https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup) 18 | 19 | These additional methods depend on a package (`stream`) that is **only available on the server**, and won’t work in the browser. 20 | 21 | - [`renderToNodeStream()`](https://reactjs.org/docs/react-dom-server.html#rendertonodestream) 22 | - [`renderToStaticNodeStream()`](https://reactjs.org/docs/react-dom-server.html#rendertostaticnodestream) 23 | 24 | ---------- 25 | 26 | ## [Reference](https://reactjs.org/docs/react-dom-server.html#reference) 27 | 28 | ### [`renderToString()`](https://reactjs.org/docs/react-dom-server.html#rendertostring) 29 | 30 | ``` 31 | ReactDOMServer.renderToString(element) 32 | ``` 33 | 34 | Render a React element to its initial HTML. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes. 35 | 36 | If you call [`ReactDOM.hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience. 37 | 38 | ---------- 39 | 40 | ### [`renderToStaticMarkup()`](https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup) 41 | 42 | ``` 43 | ReactDOMServer.renderToStaticMarkup(element) 44 | ``` 45 | 46 | Similar to [`renderToString`](https://reactjs.org/docs/react-dom-server.html#rendertostring), except this doesn’t create extra DOM attributes that React uses internally, such as `data-reactroot`. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes. 47 | 48 | If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToString`](https://reactjs.org/docs/react-dom-server.html#rendertostring) on the server and [`ReactDOM.hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) on the client. 49 | 50 | ---------- 51 | 52 | ### [`renderToNodeStream()`](https://reactjs.org/docs/react-dom-server.html#rendertonodestream) 53 | 54 | ``` 55 | ReactDOMServer.renderToNodeStream(element) 56 | ``` 57 | 58 | Render a React element to its initial HTML. Returns a [Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams) that outputs an HTML string. The HTML output by this stream is exactly equal to what [`ReactDOMServer.renderToString`](https://reactjs.org/docs/react-dom-server.html#rendertostring) would return. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes. 59 | 60 | If you call [`ReactDOM.hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience. 61 | 62 | > Note: 63 | > 64 | > Server-only. This API is not available in the browser. 65 | > 66 | > The stream returned from this method will return a byte stream encoded in utf-8. If you need a stream in another encoding, take a look at a project like [iconv-lite](https://www.npmjs.com/package/iconv-lite), which provides transform streams for transcoding text. 67 | 68 | ---------- 69 | 70 | ### [`renderToStaticNodeStream()`](https://reactjs.org/docs/react-dom-server.html#rendertostaticnodestream) 71 | 72 | ``` 73 | ReactDOMServer.renderToStaticNodeStream(element) 74 | ``` 75 | 76 | Similar to [`renderToNodeStream`](https://reactjs.org/docs/react-dom-server.html#rendertonodestream), except this doesn’t create extra DOM attributes that React uses internally, such as `data-reactroot`. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes. 77 | 78 | The HTML output by this stream is exactly equal to what [`ReactDOMServer.renderToStaticMarkup`](https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup) would return. 79 | 80 | If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToNodeStream`](https://reactjs.org/docs/react-dom-server.html#rendertonodestream) on the server and [`ReactDOM.hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) on the client. 81 | 82 | > Note: 83 | > 84 | > Server-only. This API is not available in the browser. 85 | > 86 | > The stream returned from this method will return a byte stream encoded in utf-8. If you need a stream in another encoding, take a look at a project like [iconv-lite](https://www.npmjs.com/package/iconv-lite), which provides transform streams for transcoding text. -------------------------------------------------------------------------------- /readme/Reconcillation.md: -------------------------------------------------------------------------------- 1 | # Reconciliation 2 | 3 | React provides a declarative API so that you don’t have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React’s “diffing” algorithm so that component updates are predictable while being fast enough for high-performance apps. 4 | 5 | ## Motivation 6 | 7 | When you use React, at a single point in time you can think of the `render()` function as creating a tree of React elements. On the next state or props update, that `render()` function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree. 8 | 9 | There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the [state of the art algorithms](https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n3) where n is the number of elements in the tree. 10 | 11 | If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions: 12 | 13 | 1. Two elements of different types will produce different trees. 14 | 2. The developer can hint at which child elements may be stable across different renders with a `key` prop. 15 | 16 | In practice, these assumptions are valid for almost all practical use cases. 17 | 18 | ### Elements Of Different Types 19 | 20 | Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from `` to ``, or from `
` to ``, or from ` 77 | 78 | ); 79 | } 80 | } 81 | ``` 82 | 83 | Here is how we can test it: 84 | 85 | ``` 86 | import React from 'react'; 87 | import ReactDOM from 'react-dom'; 88 | import { act } from 'react-dom/test-utils'; 89 | import Counter from './Counter'; 90 | 91 | let container; 92 | 93 | beforeEach(() => { 94 | container = document.createElement('div'); 95 | document.body.appendChild(container); 96 | }); 97 | 98 | afterEach(() => { 99 | document.body.removeChild(container); 100 | container = null; 101 | }); 102 | 103 | it('can render and update a counter', () => { 104 | // Test first render and componentDidMount 105 | act(() => { 106 | ReactDOM.render(, container); 107 | }); 108 | const button = container.querySelector('button'); 109 | const label = container.querySelector('p'); 110 | expect(label.textContent).toBe('You clicked 0 times'); 111 | expect(document.title).toBe('You clicked 0 times'); 112 | 113 | // Test second render and componentDidUpdate 114 | act(() => { 115 | button.dispatchEvent(new MouseEvent('click', {bubbles: true})); 116 | }); 117 | expect(label.textContent).toBe('You clicked 1 times'); 118 | expect(document.title).toBe('You clicked 1 times'); 119 | }); 120 | ``` 121 | 122 | - Don’t forget that dispatching DOM events only works when the DOM container is added to the `document`. You can use a library like [React Testing Library](https://testing-library.com/react) to reduce the boilerplate code. 123 | 124 | - The [`recipes`](https://reactjs.org/docs/testing-recipes.html) document contains more details on how `act()` behaves, with examples and usage. 125 | -------------------------------------------------------------------------------- /readme/TypeCheckingWithProtoTypes.md: -------------------------------------------------------------------------------- 1 | # Typechecking With PropTypes 2 | 3 | > Note: 4 | > 5 | > `React.PropTypes` has moved into a different package since React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types). 6 | > 7 | > We provide [a codemod script](https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactproptypes) to automate the conversion. 8 | 9 | As your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like [Flow](https://flow.org/) or [TypeScript](https://www.typescriptlang.org/) to typecheck your whole application. But even if you don’t use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special `propTypes` property: 10 | 11 | ``` 12 | import PropTypes from 'prop-types'; 13 | 14 | class Greeting extends React.Component { 15 | render() { 16 | return ( 17 |

Hello, {this.props.name}

18 | ); 19 | } 20 | } 21 | 22 | Greeting.propTypes = { 23 | name: PropTypes.string 24 | }; 25 | ``` 26 | 27 | `PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. In this example, we’re using `PropTypes.string`. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. For performance reasons, `propTypes` is only checked in development mode. 28 | 29 | ### [PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes) 30 | 31 | Here is an example documenting the different validators provided: 32 | 33 | ``` 34 | import PropTypes from 'prop-types'; 35 | 36 | MyComponent.propTypes = { 37 | // You can declare that a prop is a specific JS type. By default, these 38 | // are all optional. 39 | optionalArray: PropTypes.array, 40 | optionalBool: PropTypes.bool, 41 | optionalFunc: PropTypes.func, 42 | optionalNumber: PropTypes.number, 43 | optionalObject: PropTypes.object, 44 | optionalString: PropTypes.string, 45 | optionalSymbol: PropTypes.symbol, 46 | 47 | // Anything that can be rendered: numbers, strings, elements or an array 48 | // (or fragment) containing these types. 49 | optionalNode: PropTypes.node, 50 | 51 | // A React element. 52 | optionalElement: PropTypes.element, 53 | 54 | // A React element type (ie. MyComponent). 55 | optionalElementType: PropTypes.elementType, 56 | 57 | // You can also declare that a prop is an instance of a class. This uses 58 | // JS's instanceof operator. 59 | optionalMessage: PropTypes.instanceOf(Message), 60 | 61 | // You can ensure that your prop is limited to specific values by treating 62 | // it as an enum. 63 | optionalEnum: PropTypes.oneOf(['News', 'Photos']), 64 | 65 | // An object that could be one of many types 66 | optionalUnion: PropTypes.oneOfType([ 67 | PropTypes.string, 68 | PropTypes.number, 69 | PropTypes.instanceOf(Message) 70 | ]), 71 | 72 | // An array of a certain type 73 | optionalArrayOf: PropTypes.arrayOf(PropTypes.number), 74 | 75 | // An object with property values of a certain type 76 | optionalObjectOf: PropTypes.objectOf(PropTypes.number), 77 | 78 | // An object taking on a particular shape 79 | optionalObjectWithShape: PropTypes.shape({ 80 | color: PropTypes.string, 81 | fontSize: PropTypes.number 82 | }), 83 | 84 | // An object with warnings on extra properties 85 | optionalObjectWithStrictShape: PropTypes.exact({ 86 | name: PropTypes.string, 87 | quantity: PropTypes.number 88 | }), 89 | 90 | // You can chain any of the above with `isRequired` to make sure a warning 91 | // is shown if the prop isn't provided. 92 | requiredFunc: PropTypes.func.isRequired, 93 | 94 | // A value of any data type 95 | requiredAny: PropTypes.any.isRequired, 96 | 97 | // You can also specify a custom validator. It should return an Error 98 | // object if the validation fails. Don't `console.warn` or throw, as this 99 | // won't work inside `oneOfType`. 100 | customProp: function(props, propName, componentName) { 101 | if (!/matchme/.test(props[propName])) { 102 | return new Error( 103 | 'Invalid prop `' + propName + '` supplied to' + 104 | ' `' + componentName + '`. Validation failed.' 105 | ); 106 | } 107 | }, 108 | 109 | // You can also supply a custom validator to `arrayOf` and `objectOf`. 110 | // It should return an Error object if the validation fails. The validator 111 | // will be called for each key in the array or object. The first two 112 | // arguments of the validator are the array or object itself, and the 113 | // current item's key. 114 | customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) { 115 | if (!/matchme/.test(propValue[key])) { 116 | return new Error( 117 | 'Invalid prop `' + propFullName + '` supplied to' + 118 | ' `' + componentName + '`. Validation failed.' 119 | ); 120 | } 121 | }) 122 | }; 123 | ``` 124 | 125 | ### [Requiring Single Child](https://reactjs.org/docs/typechecking-with-proptypes.html#requiring-single-child) 126 | 127 | With `PropTypes.element` you can specify that only a single child can be passed to a component as children. 128 | 129 | ``` 130 | import PropTypes from 'prop-types'; 131 | 132 | class MyComponent extends React.Component { 133 | render() { 134 | // This must be exactly one element or it will warn. 135 | const children = this.props.children; 136 | return ( 137 |
138 | {children} 139 |
140 | ); 141 | } 142 | } 143 | 144 | MyComponent.propTypes = { 145 | children: PropTypes.element.isRequired 146 | }; 147 | ``` 148 | 149 | ### [Default Prop Values](https://reactjs.org/docs/typechecking-with-proptypes.html#default-prop-values) 150 | 151 | You can define default values for your `props` by assigning to the special `defaultProps` property: 152 | 153 | ``` 154 | class Greeting extends React.Component { 155 | render() { 156 | return ( 157 |

Hello, {this.props.name}

158 | ); 159 | } 160 | } 161 | 162 | // Specifies the default values for props: 163 | Greeting.defaultProps = { 164 | name: 'Stranger' 165 | }; 166 | 167 | // Renders "Hello, Stranger": 168 | ReactDOM.render( 169 | , 170 | document.getElementById('example') 171 | ); 172 | ``` 173 | 174 | If you are using a Babel transform like [transform-class-properties](https://babeljs.io/docs/plugins/transform-class-properties/) , you can also declare `defaultProps` as static property within a React component class. This syntax has not yet been finalized though and will require a compilation step to work within a browser. For more information, see the [class fields proposal](https://github.com/tc39/proposal-class-fields). 175 | 176 | ``` 177 | class Greeting extends React.Component { 178 | static defaultProps = { 179 | name: 'stranger' 180 | } 181 | 182 | render() { 183 | return ( 184 |
Hello, {this.props.name}
185 | ) 186 | } 187 | } 188 | ``` 189 | 190 | The `defaultProps` will be used to ensure that `this.props.name` will have a value if it was not specified by the parent component. The `propTypes` typechecking happens after `defaultProps` are resolved, so typechecking will also apply to the `defaultProps`. -------------------------------------------------------------------------------- /readme/UnControlledComponent.md: -------------------------------------------------------------------------------- 1 | # Uncontrolled Components 2 | 3 | In most cases, we recommend using [controlled components](https://reactjs.org/docs/forms.html#controlled-components) to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself. 4 | 5 | To write an uncontrolled component, instead of writing an event handler for every state update, you can [use a ref](https://reactjs.org/docs/refs-and-the-dom.html) to get form values from the DOM. 6 | 7 | For example, this code accepts a single name in an uncontrolled component: 8 | 9 | ``` 10 | class NameForm extends React.Component { 11 | constructor(props) { 12 | super(props); 13 | this.handleSubmit = this.handleSubmit.bind(this); 14 | this.input = React.createRef(); 15 | } 16 | 17 | handleSubmit(event) { 18 | alert('A name was submitted: ' + this.input.current.value); 19 | event.preventDefault(); 20 | } 21 | 22 | render() { 23 | return ( 24 |
25 | 29 | 30 |
31 | ); 32 | } 33 | } 34 | ``` 35 | 36 | 37 | 38 | Since an uncontrolled component keeps the source of truth in the DOM, it is sometimes easier to integrate React and non-React code when using uncontrolled components. It can also be slightly less code if you want to be quick and dirty. Otherwise, you should usually use controlled components. 39 | 40 | If it’s still not clear which type of component you should use for a particular situation, you might find [this article on controlled versus uncontrolled inputs](https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/) to be helpful. 41 | 42 | ### [Default Values](https://reactjs.org/docs/uncontrolled-components.html#default-values) 43 | 44 | In the React rendering lifecycle, the `value` attribute on form elements will override the value in the DOM. With an uncontrolled component, you often want React to specify the initial value, but leave subsequent updates uncontrolled. To handle this case, you can specify a `defaultValue` attribute instead of `value`. 45 | 46 | ``` 47 | render() { 48 | return ( 49 |
50 | 57 | 58 |
59 | ); 60 | } 61 | ``` 62 | 63 | Likewise, `` and `` support `defaultChecked`, and `