├── cover.jpg ├── life_cycle ├── react-delete-tree.png ├── birth │ ├── react-element-tree.png │ ├── managing_children_components_and_mounting.md │ ├── premounting_with_componentwillmount.md │ ├── component_render.md │ ├── post_mount_with_component_did_mount.md │ └── initialization_and_construction.md ├── update │ ├── react-tree-update.png │ ├── rerendering_and_children_updates.md │ ├── tapping_into_componentwillupdate.md │ ├── postrender_with_componentdidupdate.md │ ├── component_will_receive_props.md │ └── using_should_component_update.md ├── react-lifecycle-flow-chart-states.png ├── the_life_cycle_recap.md ├── death_unmounting_indepth.md ├── lifecycle_methods_overview.md ├── introduction.md ├── birth_mounting_indepth.md └── growth_update_indepth.md ├── assets └── src │ └── React Element Tree.sketch ├── patterns ├── react-indepth-avatar-list.png ├── react-indepth-details-list.png ├── component_evolution_and_composition.md ├── the_evolution_of_a_list_component.md ├── higher_order_components.md └── rendering_different_content.md ├── .gitignore ├── LICENSE ├── react_basics └── introduction.md ├── about_the_authors.md ├── SUMMARY.md └── README.md /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/cover.jpg -------------------------------------------------------------------------------- /life_cycle/react-delete-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/life_cycle/react-delete-tree.png -------------------------------------------------------------------------------- /assets/src/React Element Tree.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/assets/src/React Element Tree.sketch -------------------------------------------------------------------------------- /life_cycle/birth/react-element-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/life_cycle/birth/react-element-tree.png -------------------------------------------------------------------------------- /life_cycle/update/react-tree-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/life_cycle/update/react-tree-update.png -------------------------------------------------------------------------------- /patterns/react-indepth-avatar-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/patterns/react-indepth-avatar-list.png -------------------------------------------------------------------------------- /patterns/react-indepth-details-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/patterns/react-indepth-details-list.png -------------------------------------------------------------------------------- /life_cycle/react-lifecycle-flow-chart-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevelopmentArc/react-indepth/HEAD/life_cycle/react-lifecycle-flow-chart-states.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 DevelopmentArc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /react_basics/introduction.md: -------------------------------------------------------------------------------- 1 | # [WIP] React From The Inside Out 2 | 3 | ***This section is currently being researched*** 4 | 5 | In the meantime, there are ton of getting started resources already available. If you are new to React we recommend spending some time looking at these fantastic resources: 6 | 7 | * [React Official Site](http://facebook.github.io/react/) 8 | * [Awesome React](https://github.com/enaqx/awesome-react) - A comprehensive list of resources 9 | * [Learning React, Getting Started](https://scotch.io/tutorials/learning-react-getting-started-and-concepts) - Basic intro article 10 | 11 | From a book development perspective, our first focus will be on the [Life Cycle chapters](../life_cycle/introduction.md) and we will circle back to this section soon. 12 | 13 | ## Guiding Principals to learning React 14 | Unlike most intro books, we want to have different goals for our Basics Section. We will dig into the underpinnings of React and look at how to create applications from the bottom up. We feel that understanding the internals of a UI system helps drive development choices. We plan to explore React from this guiding principal. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /about_the_authors.md: -------------------------------------------------------------------------------- 1 | # About the Authors 2 | 3 | ### James Polanco 4 | [@jamespolanco](https://twitter.com/jamespolanco) 5 | 6 | In his role as co-founder and CTO of DevelopmentArc®, James strives to take powerful business ideas and integrate them into elegant technological experiences to help clients achieve their overall strategic goals. Since 1996, James has helped plan, guide and create interactive and web-based solutions for companies including Adobe, Toyota Motor Sports, BlueKai, VMWare, Macromedia, and DHAP Digital. James is also an international speaker, presenting on technology implementations & processes and a published author on the topic of full team product development and company workflows. 7 | 8 | 9 | ### Aaron Pedersen 10 | [@aaronpedersen](https://twitter.com/aaronpedersen) 11 | 12 | As co-founder and CEO of DevelopmentArc®, a boutique development firm and parent company of Pedanco, Aaron Pedersen’s passion lies in helping businesses streamline process making teams work more effectively through innovative technology solutions. A published author, expert speaker, and sought-after business consultant and trainer, Aaron works with a wide range of companies, from Fortune 500 corporations and multi-chain hospitality companies to emerging brands and seed-round startups including Toyota Motor Sports, DHAP Digital, Adobe, KitchenNetwork and FitStar. -------------------------------------------------------------------------------- /life_cycle/update/rerendering_and_children_updates.md: -------------------------------------------------------------------------------- 1 | # Re-rendering and Children Updates 2 | Once again we return to `render()`. Now that our `props` and `state` are all updated[^1] we can apply them to our content and children. Just like the initial render,[ all the same rules and conditions apply](../birth/component_render.md). 3 | 4 | Unlike our first render, React performs different management when it comes to the generated Elements. The main difference is around the initialization phase and children Elements of the Component. 5 | 6 | ![](react-tree-update.png) 7 | 8 | React compares the current Element tree structure returned from the `render()` method. React uses the generated keys (or assigned keys) to match each Element to a Component instance. React determines if we have new instances (**A.3**), removing instances (**A.0.1**) or are updating existing instances (**A**, **A.0**, **A.0.0**). 9 | 10 | If the keys are the same, then React will pass the `props` to the existing instance, kicking off its Update life cycle. If we have added new Components or changed keys, React will create new instances from the Element data. These new Components then enter the Birth/Mounting phase. 11 | 12 | ***Up Next:*** [Post-Render with `componentDidUpdate()`](postrender_with_componentdidupdate.md) 13 | 14 | --- 15 | 16 | [^1] As mentioned earlier, the asynchronicity nature of state is now fully applied and can be accessed safely. 17 | 18 | 19 | -------------------------------------------------------------------------------- /life_cycle/birth/managing_children_components_and_mounting.md: -------------------------------------------------------------------------------- 1 | # Managing Children Components and Mounting 2 | Now that we have completed the first render pass, our `render()` method returns a single React Element. This Element may have children elements. Those children may also have children, and so on. 3 | 4 | ![React Element Tree](react-element-tree.png) 5 | 6 | With the potential for an *n* depth tree of Elements, each of the Elements need to go through their own entire life cycle process. Just like the parent Element, React creates a new instance for each child. They go through construction, default props, initial state, `componentWillMount()` and `render()`. If the child has children, the process starts again...all the way down. 7 | 8 | One of the most powerful concepts in React is the ability to easily compose complex layout through nesting of children. It is encouraged to keep your Components as *'dumb'* as possible. The idea is to only have container[^1] components managing higher level functionality. 9 | 10 | Because this is the preferred way of development, this means we will have a lot of smaller components that also have their own life cycle. Keep this in mind as we continue through the life cycle, because every Component will follow the same pattern. 11 | 12 | ***Up Next:*** [Post-Mount with `componentDidMount()`](post_mount_with_component_did_mount.md) 13 | 14 | --- 15 | 16 | [^1] See [Presentational and Container Components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.pnmirdrso) by Dan Abramov for more details 17 | -------------------------------------------------------------------------------- /life_cycle/the_life_cycle_recap.md: -------------------------------------------------------------------------------- 1 | # The Life Cycle Recap 2 | We have now worked through the three phases of the React life cycle: [Birth/Mounting](birth_mounting_indepth.md), [Growth/Update](growth_update_indepth.md) and finally [Death/Unmount](death_unmounting_indepth.md). By having these phases and corresponding methods React provides us a clear path for developing Components. These phases also allow us to begin to optimize our Components and our entire application. 3 | 4 | To review, the methods and order called are: 5 | 6 | ## Birth / Mounting 7 | 1. Initialize / Construction 8 | 2. `getDefaultProps()` *(React.createClass)* or `MyComponent.defaultProps` *(ES6 class)* 9 | 3. `getInitialState()` *(React.createClass)* or `this.state = ...` *(ES6 constructor)* 10 | 4. `componentWillMount()` 11 | 5. `render()` 12 | 6. Children initialization & life cycle kickoff 13 | 7. `componentDidMount()` 14 | 15 | ## Growth / Update 16 | 1. `componentWillReceiveProps()` 17 | 2. `shouldComponentUpdate()` 18 | 3. `componentWillUpdate()` 19 | 3. `render()` 20 | 4. Children Life cycle methods 21 | 5. `componentDidUpdate()` 22 | 23 | ## Death / Un-Mounting 24 | 1. `componentWillUnmount()` 25 | 4. Children Life cycle methods 26 | 5. Instance destroyed for Garbage Collection 27 | 28 | ## Life Cycle Flowchart and `setState()` safety 29 | 30 | In addition, this flow chart by [Peter Beshai](https://twitter.com/pbesh) breaks down the different methods and also calls out when `this.setState()` is safe and NOT safe to call: 31 | 32 | ![Lifecycl Flow Chart](react-lifecycle-flow-chart-states.png) -------------------------------------------------------------------------------- /life_cycle/death_unmounting_indepth.md: -------------------------------------------------------------------------------- 1 | # Death/Unmount In-depth 2 | After our Component has spent time in the Update phase, we eventually enter the Death phase. During this phase our component is Unmounted from the Native UI stack and is marked for Garbage Collection. 3 | 4 | We enter this phase when our UI changes and the Element Tree no longer has a matching key to our Component. This could be changing layout or programmatically changing keys (forcing a new Component instance to be created). Once this occurs, React looks at the instance being removed and its children. 5 | 6 | ## Using `componentWillUnmount()` 7 | Just like the rest of our life cycle phases, the Death/Unmount phase has a method hook for us. This method allows us to do some cleanup before we are removed from the UI stack. Typically we want to reverse any setup we did in either `componentWillMount()` or `componentDidMount()`. 8 | 9 | For example, we would want to unregister any global/system/library events, destroy 3rd party UI library elements, etc. If we don't take the time to remove events we can create memory leaks in our system or leave bad references laying around. 10 | 11 | ![](react-delete-tree.png) 12 | 13 | React starts with the Element being removed, for example **A.0**, and calls `componentWillUnmount()` on it. Then React goes to the first child (**A.0.0**) and does the same, working its way down to the last child. Once all the calls have been made, React will remove the Components from the UI and ready them for Garbage Collection. 14 | 15 | ***Up Next:*** [The Life Cycle Recap](the_life_cycle_recap.md) 16 | -------------------------------------------------------------------------------- /life_cycle/lifecycle_methods_overview.md: -------------------------------------------------------------------------------- 1 | # React Life Cycle Methods Overview 2 | The React development team provides a series of hooks we can tap into at each phase of the life cycle. These method hooks inform us of where the Component is in the life cycle and what we can and cannot do. 3 | 4 | Each of the life cycle methods are called in a specific order and at a specific time. The methods are also tied to different parts of the life cycle. Here are the methods broken down in order and by their corresponding life cycle phase [^1]: 5 | 6 | ## Birth / Mounting 7 | 1. Initialize / Construction 8 | 2. `getDefaultProps()` *(React.createClass)* or `MyComponent.defaultProps` *(ES6 class)* 9 | 3. `getInitialState()` *(React.createClass)* or `this.state = ...` *(ES6 constructor)* 10 | 4. `componentWillMount()` 11 | 5. `render()` 12 | 6. Children initialization & life cycle kickoff 13 | 7. `componentDidMount()` 14 | 15 | ## Growth / Update 16 | 1. `componentWillReceiveProps()` 17 | 2. `shouldComponentUpdate()` 18 | 3. `componentWillUpdate()` 19 | 3. `render()` 20 | 4. Children Life cycle methods 21 | 5. `componentDidUpdate()` 22 | 23 | ## Death / Unmount 24 | 1. `componentWillUnmount()` 25 | 4. Children Life cycle methods 26 | 5. Instance destroyed for Garbage Collection 27 | 28 | The order of these methods are strict and called as defined above. Most of the time is spent in the Growth/Update phase and those methods are called many times. The Birth and Death methods will only be called once. 29 | 30 | ***Next Up***: [Birth/Mounting in-depth](birth_mounting_indepth.md) 31 | 32 | --- 33 | 34 | [^1] *Most of the methods are the same if you use either `React.createClass` or use ES6 classes, such as `class MyComponent extends React.Component`. A few are different, mainly around how instantiation/creation occurs. We will call these differences out throughout the chapter.* 35 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [[WIP] React From the Inside Out](react_basics/introduction.md) 5 | * [The React Life Cycle](life_cycle/introduction.md) 6 | * [Life Cycle Methods Overview](life_cycle/lifecycle_methods_overview.md) 7 | * [Birth/Mounting In-depth](life_cycle/birth_mounting_indepth.md) 8 | * [Initialization & Construction](life_cycle/birth/initialization_and_construction.md) 9 | * [Pre-Mounting with componentWillMount()](life_cycle/birth/premounting_with_componentwillmount.md) 10 | * [Component render()](life_cycle/birth/component_render.md) 11 | * [Managing Component Children and Mounting](life_cycle/birth/managing_children_components_and_mounting.md) 12 | * [Post-Mount with componentDidMount()](life_cycle/birth/post_mount_with_component_did_mount.md) 13 | * [Growth/Update In-depth](life_cycle/growth_update_indepth.md) 14 | * [Updating and componentWillReceiveProps()](life_cycle/update/component_will_receive_props.md) 15 | * [Using shouldComponentUpdate()](life_cycle/update/using_should_component_update.md) 16 | * [Tapping into componentWillUpdate()](life_cycle/update/tapping_into_componentwillupdate.md) 17 | * [Re-rendering and Children Updates](life_cycle/update/rerendering_and_children_updates.md) 18 | * [Post-Render with componentDidUpdate()](life_cycle/update/postrender_with_componentdidupdate.md) 19 | * [Death/Unmount In-depth](life_cycle/death_unmounting_indepth.md) 20 | * [The Life Cycle Recap](life_cycle/the_life_cycle_recap.md) 21 | * [Component Evolution and Composition](patterns/component_evolution_and_composition.md) 22 | * [The Evolution of a List Component](patterns/the_evolution_of_a_list_component.md) 23 | * [Rendering different content](patterns/rendering_different_content.md) 24 | * [Higher Order Components](patterns/higher_order_components.md) 25 | * [About the Authors](about_the_authors.md) 26 | 27 | -------------------------------------------------------------------------------- /life_cycle/introduction.md: -------------------------------------------------------------------------------- 1 | # The React Life Cycle 2 | One of the defining factors of a life form is its life cycle. The common path is Birth, Growth into maturity and then the inevitable Death. UI applications often follow a similar path. When the application is first started, we consider this Birth. The users interacts with application, which is Growth. Eventually, the application is closed or navigated away from, leading to Death. 3 | 4 | Within the application, elements also follow this pattern. In the world of React, these elements are our Components. The Component life cycle is a continuous process, which occurs throughout the overall life of our application. Understanding this process can lead to faster and consistent development, easier optimization and improved overall application health. 5 | 6 | ## Life cycle phases in React components 7 | Not all UI systems enable a life cycle pattern. This doesn't mean that a system is better or worse if a life cycle is or isn't implemented. All a life cycle does is provide a specific order of operation and a series of hooks to tie into said system. The React life cycle follows the common Birth, Growth, and Death flow. The React team has provided a series of methods you can implement/override to tap into the process. 8 | 9 | ### [Phase 1: Birth / Mounting](birth_mounting_indepth.md) 10 | The first phase of the React Component life cycle is the Birth/Mounting phase. This is where we start initialization of the Component. At this phase, the Component's `props` and `state` are defined and configured. The Component and all its children are mounted on to the Native UI Stack (DOM, UIView, etc.). Finally, we can do post-processing if required. The Birth/Mounting phase only occurs once. 11 | 12 | ### [Phase 2: Growth / Update](growth_update_indepth.md) 13 | The next phase of the life cycle is the Growth/Update phase. In this phase, we get new `props`, change `state`, handle user interactions and communicate with the component hierarchy. This is where we spend most of our time in the Component's life. Unlike Birth or Death, we repeat this phase over and over. 14 | 15 | ### [Phase 3: Death / Unmount](death_unmounting_indepth.md) 16 | The final phase of the life cycle is the Death/Unmount phase. This phase occurs when a component instance is unmounted from the Native UI. This can occur when the user navigates away, the UI page changes, a component is hidden (like a drawer), etc. Death occurs once and readies the Component for Garbage Collection. 17 | 18 | ***Next Up:*** [Life Cycle Methods Overview](lifecycle_methods_overview.md) 19 | -------------------------------------------------------------------------------- /patterns/component_evolution_and_composition.md: -------------------------------------------------------------------------------- 1 | # Component Evolution and Composition 2 | Component reuse and composability are some of the core tenets of React development. As our applications scale, development time can be dramatically reduced through this process. Yet, creating reusable Components takes planning and understanding to support multiple use cases. 3 | 4 | Understanding the intention of the Component is the first step towards reuse. Sometimes, we know a Component will be used in many different ways from the start. In those situations, we can plan for the different scenarios right away. In other situations, Component intentions will change over the lifespan of the application. Understanding how to evolve a Component is just as important as understanding how to create reusability. 5 | 6 | ##The Application Architecture process 7 | 8 | Let's take a quick moment and discuss the process of application architecture. We often hear about over-architected systems. This often occurs when we try to plan for every possible scenario that could ever occur through the life of an application. To try and support every conceivable use is a fools errand. When we try to build these systems we add unnecessary complexity and often make development harder, rather then easier. 9 | 10 | At the same time, we don't want to build a system that offers no flexibility at all. It may be faster to just build it without future thought, but adding new features can be just as time consuming later on. Trying to find the right balance is the hardest part of application architecture. We want to create a flexible application that allows growth but we don't want to waste time on all possibilities. 11 | 12 | The other challenge with application architecture is trying to understand our needs. With development, we often have to build out something to truly understand it. This means that our application architecture is a living process. It changes over time due to having a better understanding of what's required. Refactoring Components is critical to the success of a project and makes adding new features easier. 13 | 14 | Because of this process, we felt it is important to walk through the evolution of a Component. 15 | We will start with a naive approach to building a List Component and then walk through different refactorings to support reusability. More then likely, we would know early on that a List should be reusable. But, walking through the evolution process can help deepen our understanding of how to enable reusability. 16 | 17 | ***Up Next***: [The Evolution of a List Component](the_evolution_of_a_list_component.md) 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React In-depth: An exploration of UI development 2 | At [DevelopmentArc®](http://developmentarc.com) we have a love affair with UI application development. We truly enjoy the exploration of technologies and frameworks. This process helps us better understand the end-goals and complexity of the application stack. 3 | 4 | We discovered early on the need to apply true software development principles to the user interface. This discovery started a long time ago with technologies like Authorware/Toolbook and Director. Quickly we moved to HTML 1.0 and began to build systems with JavaScript frameworks like Prototype.js. With the release of the Flex framework, our focus again shifted to a new platform, Flash. 5 | 6 | For a majority, Flash was a negative experience and UI technology. While many arguments are true, we found Flash to be the most advanced cross-platform rendering system available at the time. Flex gave us the application framework necessary to build the large and complex applications clients were requesting. All the while, Flex lent itself to the management of large and diverse teams. Our obsession with Flex included a deep understand of the application and component life cycles, resulting in a 90-page white paper. The paper is still available and continues to be referenced today. With the collapse of the Flash Platform and Flex, we find ourselves back in HTML and JavaScript world. This time our obsession is [React.js](https://facebook.github.io/react/) 7 | 8 | Throughout the years we have continued to try and push the boundaries of UI technologies. Starting, in late 2014, we began initial research and then full adoption of [React.js](https://facebook.github.io/react/) for our UI layer in for web applications. 9 | 10 | The initial process of moving to React was a blend of excitement and at times, pure frustration. React brings in both existing UI paradigms and also new patterns that can take a bit of time to adjust your own mind-set to. Once we had fully grokked React, we found that it has opened the possibilities for our current and future projects. 11 | 12 | Our goal with this GitBook is to document our process, share our research and try to organize our experiences into a single living document. Too be honest, this is a pretty lofty goal. We may not achieve this goal, but hopefully we can get some helpful thoughts down. 13 | 14 | We have found the longer you write code, the more you learn and then shortly forget. This means that our writings are just as much for ourselves as for others. With that in mind we hope that as this document grows it will help you, just as much as it helped us to put our own thoughts down. 15 | 16 | *James & Aaron* 17 | -------------------------------------------------------------------------------- /life_cycle/birth/premounting_with_componentwillmount.md: -------------------------------------------------------------------------------- 1 | # Pre-mounting with `componentWillMount()` 2 | Now that the props and state are set, we finally enter the realm of Life Cycle methods. The first true life cycle method called is `componentWillMount()`. This method is only called one time, which is before the initial render. Since this method is called before `render()` our Component will not have access to the Native UI (DOM, etc.). We also will not have access to the children `refs`, because they are not created yet. 3 | 4 | The `componentWillMount()` is a chance for us to handle configuration, update our state, and in general prepare for the first render. At this point, props and initial state are defined. We can safely query `this.props` and `this.state`, knowing with certainty they are the current values. This means we can start performing calculations or processes based on the prop values. 5 | 6 | **Person.js [^1]** 7 | ```javascript 8 | import React from 'react'; 9 | import classNames from 'classnames'; 10 | 11 | class Person extends React.Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { mode: undefined } ; 15 | } 16 | 17 | componentWillMount() { 18 | let mode; 19 | if (this.props.age > 70) { 20 | mode = 'old'; 21 | } else if (this.props.age < 18) { 22 | mode = 'young'; 23 | } else { 24 | mode = 'middle'; 25 | } 26 | this.setState({ mode }); 27 | } 28 | 29 | render() { 30 | return ( 31 |
32 | { this.props.name } (age: { this.props.age }) 33 |
34 | ); 35 | } 36 | } 37 | 38 | Person.defaultProps = { age: 'unknown' }; 39 | 40 | export default Person; 41 | ``` 42 | 43 | In the example above we call `this.setState()` and update our current state before render. If we need state values on calculations passed in `props`, this is where we should do the logic. 44 | 45 | Other uses for `componentWillMount()` includes registering to global events, such as a Flux store. If your Component needs to respond to global Native UI events, such as `window` resizing or focus changes, this is a good place to do it[^2]. 46 | 47 | ***Next Up:*** [Component `render()`](component_render.md) 48 | 49 | --- 50 | [^1] In our example above, we are using the `classNames()` library, which was originally included as a React Addon. However, the feature has been removed from React and moved to its [own library](https://github.com/JedWatson/classnames) for use with or without React. 51 | 52 | [^2] It's important to remember that many Native UI elements do not exist at this point in the life cycle. That means we need to stick to very high-level/global events such as `window` or `document`. 53 | -------------------------------------------------------------------------------- /life_cycle/update/tapping_into_componentwillupdate.md: -------------------------------------------------------------------------------- 1 | # Tapping into `componentWillUpdate()` 2 | Once we have determined that we do need to re-render in our Update phase, the `componentWillUpdate()` will be called. The method is passed in two arguments: `nextProps` and `nextState`. The method `componentWillUpdate()` is [similar to `componentWillMount()`](../birth/premounting_with_componentwillmount.md), and many of the same considerations and tasks are the same. The difference being that `componentWillUpdate()` is called every time a re-render is required, such as when `this.setState()` is called. Unlike `componentWillMount()` we get access to the next `props` and `state`. 3 | 4 | Just like `componentWillMount()`, this method is called before `render()`. Because we have not rendered yet, our Component's access to the Native UI (DOM, etc.) will reflect the old rendered UI. Unlike `componentWillMount()`, we can access `refs` but in general this is not recommended because the refs will soon be out of date. There are use cases for accessing the Native UI here, such as starting animations. 5 | 6 | The `componentWillUpdate()` is a chance for us to handle configuration changes and prepare for the next render. If we want to access the old props or state, we can call `this.props` or `this.state`. We can then compare them to the new values and make changes/calculations as required. 7 | 8 | Unlike `componentWillMount()`, we should not call `this.setState()` here. The reason we do not call `this.setState()` is that the method triggers another `componentWillUpdate()`. If we trigger a state change in `componentWillUpdate()` we will end up in an infinite loop [^1]. 9 | 10 | Some of the more common uses for `componentWillUpdate()` is to set a variable based on state changes (not using `this.setState()`), dispatching events or starting animations [^2]. 11 | 12 | ```javascript 13 | // dispatching an action based on state change 14 | componentWillUpdate(nextProps, nextState) { 15 | if (nextState.open == true && this.state.open == false) { 16 | this.props.onWillOpen(); 17 | } 18 | } 19 | ``` 20 | 21 | ***Up Next:*** [Re-rendering and Children Updates](rerendering_and_children_updates.md) 22 | 23 | --- 24 | 25 | [^1] In the previous version of this section we mistakenly said that you can safely call `setState()` in this method. Our assumption at the time was that a dirty flag was tracking the current state of the render pass, but this is not the case. It is technically possible to call `setState()` behind a conditional (such as when a prop/state changes) but it is **not** recommended and should be considered a no go. Special thanks to [Robin Venneman](https://github.com/robinvenneman) for catching this error and calling it to our attention! 26 | 27 | [^2] An example of triggering CSS transitions in `componentWillUpdate()` and other discussions around this method's usages is over at this [StackOverflow response](http://stackoverflow.com/a/33075514/815544). 28 | -------------------------------------------------------------------------------- /life_cycle/update/postrender_with_componentdidupdate.md: -------------------------------------------------------------------------------- 1 | # Post-Render with `componentDidUpdate()` 2 | Continuing the trend of corresponding methods, the `componentDidUpdate()` is the Update version of [`componentDidMount()`](../birth/post_mount_with_component_did_mount.md). Once again, we can access the Native UI stack, interact with our `refs` and if required start another re-render/update [^1]. 3 | 4 | When `componentDidUpdate()` is called, two arguments are passed: `prevProps` and `prevState`. This is the inverse of `componentWillUpdate()`. The passed values are what the values were, and `this.props` and `this.state` are the current values. 5 | 6 | ![](react-tree-update.png) 7 | 8 | Just like `componentDidMount()`, the `componentDidUpdate()` is called after all of the children are updated. Just to refresh your memory, **A.0.0** will have `componentDidUpdate()` called first, then **A.0**, then finally **A**. 9 | 10 | ## Common Tasks 11 | The most common uses of `componentDidUpdate()` is managing 3rd party UI elements and interacting with the Native UI. When using 3rd Party libraries, like our Chart example, we need to update the UI library with new data. 12 | 13 | ```javascript 14 | componentDidUpdate(prevProps, prevState) { 15 | // only update chart if the data has changed 16 | if (prevProps.data !== this.props.data) { 17 | this.chart = c3.load({ 18 | data: this.props.data 19 | }); 20 | } 21 | } 22 | ``` 23 | 24 | Here we access our Chart instance and update it when the data has changed[^2]. 25 | 26 | ### Another render pass? 27 | We can also query the Native UI and get sizing, CSS styling, etc. This may require us to update our internal state or `props` for our children. If this is the case we can call `this.setState()` or `forceUpdate()` here, but this opens a lot of potential issues because it forces a new render pass. 28 | 29 | One of the worst things to do is do an unchecked `setState()`: 30 | 31 | ```javascript 32 | componentDidUpdate(prevProps, prevState) { 33 | // BAD: DO NOT DO THIS!!! 34 | let height = ReactDOM.findDOMNode(this).offsetHeight; 35 | this.setState({ internalHeight: height }); 36 | } 37 | ``` 38 | 39 | By default, our `shouldComponentUpdate()` returns true, so if we used the above code we would fall into an infinite render loop. We would render, then call did update which sets state, triggering another render. 40 | 41 | If you need to do something like this, then you can implement a check at `componentDidUpdate()` and/or add other checks to determine when a re-size really occurred. 42 | 43 | ```javascript 44 | componentDidUpdate(prevProps, prevState) { 45 | // One possible fix... 46 | let height = ReactDOM.findDOMNode(this).offsetHeight; 47 | if (this.state.height !== height ) { 48 | this.setState({ internalHeight: height }); 49 | } 50 | } 51 | ``` 52 | 53 | In general, this is not a common requirement and re-rendering has performance impacts for your Component and applications. Keep this in mind if you find yourself having to add a second render pass in `componentDidUpdate()`. 54 | 55 | ***Up Next:*** [Death/Unmounting In-depth](../death_unmounting_indepth.md) 56 | 57 | --- 58 | 59 | [^1] This is a risky behavior and can easily enter an infinite loop. Proceed with caution! 60 | 61 | [^2] This example assumes that the data is pure and not mutated. 62 | -------------------------------------------------------------------------------- /life_cycle/birth/component_render.md: -------------------------------------------------------------------------------- 1 | # Component `render()` 2 | Now that we have pre-configured our Component, we enter the first rendering of our content. As React developers, the `render()` method is the most familiar. We create Elements (generally via JSX) and return them. We access the Component `this.props` and `this.state` and let these values derive how content should be generated. When we access `this.state`, any changes we made during `componentWillMount()` are fully applied. 3 | 4 | Unlike any other method in the Life Cycle, `render()` is the one method that exists across multiple life cycle phases. It occurs here in Birth and it is where we spend a lot of time in Growth. 5 | 6 | In both cases, we have the core principle of keeping `render()` a pure method. What does that mean? That means we shouldn't call `setState()`, query the Native UI or anything else that can mutate the existing state of the application. The reason why is if we do this kind of interaction in `render()`, then it will kickoff another render pass. Which once again, triggers `render()` which then does the same thing... infinitely. 7 | 8 | The React development mode[^1] is generally great at catching these kinds of errors and will yell at you if you do them. For example, if we did something silly like this 9 | 10 | ```javascript 11 | render() { 12 | // BAD: Do not do this! 13 | this.setState({ foo: 'bar' }); 14 | return ( 15 |
16 | { this.props.name } (age: { this.props.age }) 17 |
18 | ); 19 | } 20 | ``` 21 | 22 | React would log out the following statement: 23 | 24 | > Warning: setState(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state. 25 | 26 | ## Native UI access in `render()` is often fatal 27 | React will also warn you if you try to access the Native UI elements in the render pass. 28 | 29 | ```javascript 30 | render() { 31 | // BAD: Don't do this either! 32 | let node = ReactDOM.findDOMNode(this); 33 | return ( 34 |
35 | { this.props.name } (age: { this.props.age }) 36 |
37 | ); 38 | } 39 | ``` 40 | 41 | > VM943:45 Warning: Person is accessing getDOMNode or findDOMNode inside its render(). render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead. 42 | 43 | In the above example, it may seem safe since you are just querying the node. But, as the warning states, we might be querying potentially old data. But in our case, during the Birth phase, this would be a fatal error. 44 | 45 | > Uncaught Invariant Violation: findComponentRoot(..., .0): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a>, or using non-SVG elements in an <svg> parent. Try inspecting the child nodes of the element with React ID `Person`. 46 | 47 | This is one of those cases where the React error doesn't clearly point to the cause of the problem. In our case we didn't modify the DOM, so it feels like an unclear and potentially misleading error. This kind of error can cause React developers a lot of pain early on. Because we instinctually look for a place where we are changing the Native UI. 48 | 49 | The reason we get this error is because during the first render pass the Native UI elements we are trying to access do not exist yet. We are essentially asking React to find a DOM node that doesn't exist. Generally, when `ReactDOM` can't find the node, this is because something or someone mutated the DOM. So, React falls back to the most common cause. 50 | 51 | As you can see, having an understanding of the Life Cycle can help troubleshoot and prevent these often un-intuitive issues. 52 | 53 | ***Up Next:***[ Managing Children Components and Mounting](managing_children_components_and_mounting.md) 54 | 55 | --- 56 | [^1] These warnings come out of the development mode in React. You can also use the [React Development Tools](https://github.com/facebook/react-devtools) to help debug and explore React components. 57 | -------------------------------------------------------------------------------- /life_cycle/birth_mounting_indepth.md: -------------------------------------------------------------------------------- 1 | # Birth/Mounting In-depth 2 | A React Component kicks off the life cycle during the initial application ex: `ReactDOM.render()`. With the initialization of the component instance, we start moving through the Birth phase of the life cycle. Before we dig deeper into the mechanics of the Birth phase, let's step back a bit and talk about what this phase focuses on. 3 | 4 | The most obvious focus of the birth phase is the initial configuration for our Component instance. This is where we pass in the `props` that will define the instance. But during this phase there are a lot more moving pieces that we can take advantage of. 5 | 6 | In Birth we configure the default `state` and get access to the initial UI display. It also starts the mounting process for children of the Component. Once the children mount, we get first access to the Native UI layer[^1] (DOM, UIView, etc.). With Native UI access, we can start to query and modify how our content is actually displayed. This is also when we can begin the process of integrating 3rd Party UI libraries and components. 7 | 8 | ## Components vs. Elements 9 | When learning React, many developers have a common misconception. At first glance, one would assume that a mounted instance is the same as a component class. For example, if I create a new React component and then `render()` it to the DOM: 10 | 11 | ```javascript 12 | import React from 'react'; 13 | import ReactDOM from 'react-dom'; 14 | 15 | class MyComponent extends React.Component { 16 | render() { 17 | return
Hello World!
; 18 | } 19 | }; 20 | 21 | ReactDOM.render(, document.getElementById('mount-point')); 22 | ``` 23 | 24 | The initial assumption is that during `render()` an instance of the `MyComponent` class is created, using something like `new MyComponent()`. This instance is then passed to render. Although this sounds reasonable, the reality of the process is a little more involved. 25 | 26 | What is actually occurring is the JSX processor converts the `` line to use `React.createElement` to generate the instance. This generated Element is what is passed to the `render()` method: 27 | 28 | ```javascript 29 | // generated code post-JSX processing 30 | ReactDOM.render( 31 | React.createElement(MyComponent, null), document.getElementById('mount-point') 32 | ); 33 | ``` 34 | 35 | A React Element is really just a description[^2] of what will eventually be used to generate the Native UI. This is a core, pardon the pun, *element* of virtual DOM technology in React. 36 | 37 | 38 | > The primary type in React is the ReactElement. It has four properties: type, props, key and ref. It has no methods and nothing on the prototype. 39 | > 40 | > -- https://facebook.github.io/react/docs/glossary.html#react-elements 41 | 42 | 43 | The Element is a lightweight object representation of what will become the component instance. If we try to access the Element thinking it is the Class instance we will have some issues, such as availability of expected methods. 44 | 45 | So, how does this tie into the life cycle? These descriptor Elements are essential to the creation of the Native UI and are the catalyst to the life cycle. 46 | 47 | ## The First `render()` 48 | To most React developers, the `render()` method is the most familiar. We write our JSX and layout here. It's where we spend a lot of time and drives the layout of the application. When we talk about the first `render()` this is a special version of the `render()` method that mounts our entire application on the Native UI. 49 | 50 | In the browser, this is the `ReactDOM.render()` method. Here we pass in the root Element and tell React where to mount our content. With this call, React begins processing the passed Element(s) and generate instances of our React components. The Element is used to generate the type instance and then the `props` are passed to the Component instance. 51 | 52 | This is the point where we enter the Component life cycle. React uses the `instance` property on the Element and begins construction. 53 | 54 | 55 | ***Next Up:*** [Initialization & Construction](birth/initialization_and_construction.md) 56 | 57 | --- 58 | 59 | [^1] The Native UI layer is the system that handles UI content rendering to screen. In a browser, this is the DOM. On device, this would be the UIView (or comparable). React handles the translation of Component content to the native layer format. 60 | 61 | [^2] Dan Abramov chimed in with this terminology on a StackOverflow question. http://stackoverflow.com/a/31069757 62 | -------------------------------------------------------------------------------- /life_cycle/update/component_will_receive_props.md: -------------------------------------------------------------------------------- 1 | # Updating and `componentWillReceiveProps()` 2 | Now that we have discussed starting an Update, let's dive into the Update life cycle methods. The first method available to us is `componentWillReceiveProps()`. This method is called when `props` are passed to the Component instance. Let's dig a little deeper into what this means. 3 | 4 | ## Passing `props` 5 | The most obvious example is when new `props` are passed to a Component. For example, we have a Form Component and a Person Component. The Form Component has a single `` that allows the user to change the name by typing into the input. The input is bound to the `onChange` event and sets the state on the Form. The state value is then passed to the Person component as a `prop`. 6 | 7 | ***Form.js*** 8 | ```javascript 9 | import React from 'react'; 10 | import Person from './Person'; 11 | 12 | export default class Form extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = { name: '' } ; 16 | this.handleChange = this.handleChange.bind(this); 17 | } 18 | 19 | handleChange(event) { 20 | this.setState({ name: event.currentTarget.value }); 21 | } 22 | 23 | render() { 24 | return ( 25 |
26 | 27 | 28 |
29 | ); 30 | } 31 | } 32 | ``` 33 | 34 | Any time the user types into the `` this begins an Update for the Person component. The first method called on the Component is `componentWillReceiveProps(nextProps)` passing in the new `prop` value. This allows us to compare the incoming `props` against our current `props` and make logical decisions based on the value. We can get our current props by calling `this.props` and the new value is the `nextProps` argument passed to the method. 35 | 36 | ### Updating State 37 | So why do we need `componentWillReceiveProps`? This is the first hook that allows us to look into the upcoming Update. Here we could extract the new props and update our internal state. If we have a state that is a calculation of multiple props, we can safely apply the logic here and store the result using `this.setState()`. 38 | 39 | > Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render. 40 | > 41 | > -- https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops 42 | 43 | 44 | ### Props may not change 45 | A word of caution with `componentWillReceiveProps()`. Just because this method was called, does not mean the value of props has changed. 46 | 47 | > To understand why, we need to think about what could have happened. The data could have changed between the initial render and the two subsequent updates ... React has no way of knowing that the data didn’t change. Therefore, React needs to call `componentWillReceiveProps`, because the component needs to be notified of the new props (even if the new props happen to be the same as the old props). 48 | > 49 | > -- See [(A => B) !=> (B => A)](https://facebook.github.io/react/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A.html) 50 | 51 | The core issue with `props` and `componentWillReceiveProps()` is how JavaScript provides mutable data structures. Let's say we have a prop called `data` and data is an Array. 52 | 53 | ```javascript 54 | // psuedo code 55 | this.setState({ data: [1, 2, 3] }); 56 | 57 | 58 | ``` 59 | 60 | If somewhere in our app, a process updates the data array via `push()`, this changes the content of the data Array. Yet, the Array itself is the same instance. Because it is the same instance, React can not easily determine if the internal data has changed. So, to prevent a lot of issues, or having to do deep comparisons, React will push the same props down. 61 | 62 | With this being said, `componentWillReceiveProps()` allows us to check and see if new props are coming in and we can make choices based on the data. We just need to make sure we never assume the props are different in this method. Be sure to read the great post [(A => B) !=> (B => A)](https://facebook.github.io/react/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A.html) by Jim Sproch. 63 | 64 | ### Skipping this method 65 | Unlike the other methods in the Mounting phase, not all our Update phase methods are called every time. For example, we will skip `componentWillReceiveProps()` if the Update is triggered by just a state change. Going back to our Form.js example above: 66 | 67 | ```javascript 68 | // ... 69 | handleChange(event) { 70 | this.setState({ name: event.currentTarget.value }); 71 | } 72 | 73 | render() { 74 | return ( 75 |
76 | 77 | 78 |
79 | ); 80 | } 81 | // ... 82 | ``` 83 | 84 | When the user types in the `` we trigger a `setState()` method. This will trigger an Update phase in our Form Component and the Person Component. For our Form Component, we did not receive new props, so `componentWillReceiveProps()` will be skipped. 85 | 86 | ***Up Next:*** [Using `shouldComponentUpdate()](using_should_component_update.md) 87 | -------------------------------------------------------------------------------- /life_cycle/update/using_should_component_update.md: -------------------------------------------------------------------------------- 1 | # Using `shouldComponentUpdate()` 2 | The next method in the Update life cycle is `shouldComponentUpdate()`. This method allows your Component to exit the Update life cycle if there is no reason to apply a new render. Out of the box, the `shouldComponentUpdate()` is a no-op that returns `true`. This means every time we start an Update in a Component, we will re-render. 3 | 4 | If you recall, React does [not deeply compare `props`](https://facebook.github.io/react/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A.html) by default. When `props` or `state` is updated React assumes we need to re-render the content. But, if the `props` or `state` have not changed, should we really be re-rendering? 5 | 6 | ## Preventing unnecessary renders 7 | The `shouldComponentUpdate()` method is the first real life cycle optimization method that we can leverage in React. We can look at our current and new `props` & `state` and make a choice if we should move on. [React's PureRenderMixin](https://facebook.github.io/react/docs/pure-render-mixin.html) does exactly this. It checks the current props and state, compares it to the next props and state and then returns `true` if they are different, or `false` if they are the same. 8 | 9 | ```javascript 10 | /** 11 | * Performs equality by iterating through keys on an object and returning false 12 | * when any key has values which are not strictly equal between the arguments. 13 | * Returns true when the values of all keys are strictly equal. 14 | */ 15 | function shallowEqual(objA: mixed, objB: mixed): boolean { 16 | if (objA === objB) { 17 | return true; 18 | } 19 | 20 | if (typeof objA !== 'object' || objA === null || 21 | typeof objB !== 'object' || objB === null) { 22 | return false; 23 | } 24 | 25 | var keysA = Object.keys(objA); 26 | var keysB = Object.keys(objB); 27 | 28 | if (keysA.length !== keysB.length) { 29 | return false; 30 | } 31 | 32 | // Test for A's keys different from B. 33 | var bHasOwnProperty = hasOwnProperty.bind(objB); 34 | for (var i = 0; i < keysA.length; i++) { 35 | if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { 36 | return false; 37 | } 38 | } 39 | 40 | return true; 41 | } 42 | 43 | function shallowCompare(instance, nextProps, nextState) { 44 | return ( 45 | !shallowEqual(instance.props, nextProps) || 46 | !shallowEqual(instance.state, nextState) 47 | ); 48 | } 49 | 50 | var ReactComponentWithPureRenderMixin = { 51 | shouldComponentUpdate: function(nextProps, nextState) { 52 | return shallowCompare(this, nextProps, nextState); 53 | }, 54 | }; 55 | ``` 56 | 57 | The above code is extracted from the React addon/source[^1]. The mixin defines the `shouldComponentUpdate(nextProps, nextState)` and compares the instance's `props` against the `nextProp` and the `state` against the `nextState`. 58 | 59 | ### Mutability and pure methods 60 | It is important to note that the `shallowCompare` method simply uses `===` to check each instance. This is why the React team calls the mixin *pure*, because it will not properly check against mutable data. 61 | 62 | Let's think back to our `data` props Array example where we use `push()` to add a new piece of data onto the Array. 63 | 64 | ```javascript 65 | // psuedo code 66 | this.setState({ data: [1, 2, 3] }); 67 | 68 | 69 | ``` 70 | 71 | The `shallowCompare` will see the current `props.data` as the same instance as the `nextProps.data` (`props.data === nextProps.data`) and therefore not render an update. Since we mutated the `data` Array, our code is **not** considered to be *pure*. 72 | 73 | This is why systems like [Redux](http://redux.js.org/) requires pure methods for reducers. If you need to change nested data you have to clone the objects and make sure a new instance is always returned. This allows for `shallowCompare()` to see the change and update the component. 74 | 75 | Other ways to handle this is to use an immutable data system, such as [Immutable.js](https://facebook.github.io/immutable-js/). These data structures prevent developers from accidentally mutating data. By enforcing immutable data structures, we can leverage `shouldComponentUpdate()` and have it verify that our `props` and `state` have changed[^2]. 76 | 77 | ### Stop renders at the source 78 | If you recall our nested Component structure: 79 | 80 | ![](../birth/react-element-tree.png) 81 | 82 | By default, if an Update is triggered in **A**, then all the other children will also go through their updates. This can easily cause a performance issue, because now we have many Components going through each step of the process. 83 | 84 | By adding logic checks in `shouldComponentUpdate()` at **A** we can prevent all its children from re-rendering. This can improve overall performance significantly. But keep in mind, if you prevent **A** from passing props down to the children you may prevent required renders from occurring. 85 | 86 | ## Jump ahead with `forceUpdate()` 87 | Like `componentWillReceiveProps()`, we can skip `shouldComponentUpdate()` by calling `forceUpdate()` in the Component. This sets a flag on the Component when it gets added to the dirty queue. When flagged, `shouldComponentUpdate()` is ignored. Because we are forcing an update we are stating something has changed and the Component *must* re-render. 88 | 89 | Since `forceUpdate()` is a brute force method, it should always be used with caution and careful consideration. You can easily get into an endless render loop if you keep triggering `forceUpdate` over and over. Troubleshooting infinite render loops can be very tricky. So, when reaching for `forceUpdate` keep all this in mind. 90 | 91 | ***Next Up:*** [Tapping into `componentWillUpdate()`](tapping_into_componentwillupdate.md) 92 | 93 | --- 94 | 95 | [^1] Captured from [React 15.0.1](https://github.com/facebook/react/blob/15-stable/src/addons/shallowCompare.js) 96 | 97 | [^2] If you use Immutable.js, there is a [ImmutableRenderMixin library](https://github.com/jurassix/react-immutable-render-mixin) that provides both Object shallow compare and Immutable data comparison. 98 | -------------------------------------------------------------------------------- /life_cycle/growth_update_indepth.md: -------------------------------------------------------------------------------- 1 | # Growth/Update In-depth 2 | Once our Component is mounted in the Birth phase, we are prepped and ready for the Growth/Update phase. The Growth phase is where a Component spends most of its time. Here we get data updates, act on user or system actions and provide the overall experience for our application. 3 | 4 | The Growth phase is triggered in three different ways: changing of `props`, changing of `state` or calling `forceUpdate()`. The changes that are made affect how the Update phase is managed. We will discuss each of these changes in depth as we walk through the entire Growth process. 5 | 6 | In this Section, we will dive into the different methods. We'll examine the order of the methods called and how they affect the overall process. We will also discuss what tasks are best handled during each method and discuss application optimization. 7 | 8 | ## Starting Update: Changing Props 9 | As mentioned earlier, we have three ways to start the Growth/Update phase. The first way is when the component's `props` update. This occurs when either the root Element (ex: `ReactDOM.render(, ...)` has the `props` value changed or the parent of the Component's `prop` changes. 10 | 11 | From a Component's instance perspective (such as ``) the passed in props are immutable. In other words, the Person instance cannot update the value name internally. In fact, if you try you will get an Error in React. 12 | 13 | ```javascript 14 | render() { 15 | // BAD: DON'T DO THIS! 16 | this.props.name = 'Tim'; 17 | return ( 18 |
19 | { this.props.name } (age: { this.props.age }) 20 |
21 | ); 22 | } 23 | ``` 24 | 25 | > TypeError: Cannot assign to read only property 'name' of object '#<Object>' 26 | 27 | Because props are immutable by the Component itself, the parent must provide the new values. When new props are passed in via root or the parent, this starts the Update phase. 28 | 29 | ## Starting Update: `setState()` 30 | Similar to changing `props`, when a Component changes its state value[^1] via `this.setState()`, this also triggers a new Update phase. For a lot of React developers, the first major (and to be honest ongoing) challenge is managing state in Components. State itself can be a controversial topic in the community. Many developers avoid state at all cost. Other systems, such as [MobX](http://mobxjs.github.io/mobx/), are in essence trying to replace it. Many uses of state can fall into different anti-patterns, such as transferring `props` into `state`[^2]. 31 | 32 | Fundamentally, state can be a tricky and confusing topic. When do we use state? What data should or shouldn't be stored in state? Should we even use state at all? To be honest, this is a topic that we are still trying to grapple with ourselves. 33 | 34 | Keeping that in mind, it is still important to understand how state works in React. We will continue to discuss state in-depth and how the mechanics work. We will try to share best practices that we have found, but in general what is good today will probably be bad tomorrow. 35 | 36 | ### The asynchronicity of state 37 | Before we move on to the final way to start an update, we should talk a little about how state is managed in the internals of React. When developers first start using `setState()` there is an assumption that when you call `this.state` the values applied on the set will be available. This is not true. The `setState()` method should be treated as an asynchronous process [^3]. So how does `setState()` work? 38 | 39 | When we call `setState()` this is considered a partial state change. We are not flushing/replacing the entire state, just updating part(s) of it. React uses a queuing system[^4] to apply the partial state change. Because we can set the state multiple times in a method chain, a change queue is constructed to manage all the various updates. Once the state change is added to the queue, React makes sure the Component is added to the dirty queue. This dirty queue tracks the Component instances that have changed. Essentially, this is what tells React which Components need to enter the Update phase later. 40 | 41 | When working with state, it is very important to keep this in mind. A common error is to set state in one method and then later in the same synchronous method chain try to access the state value. This can sometimes cause tricky bugs, especially if you expose state values via public methods on your Component, such as `value()`. We will talk later about when `this.state` is finalized. 42 | 43 | ## Starting Update: `forceUpdate` 44 | There is one more way to kick off an Update phase. There is a special method on a Component called `forceUpdate()`. This does exactly what you think, it forces the Component into an Update phase. The `forceUpdate()` method has some specific ramifications about how the life cycle methods are processed and we will discuss this in-depth later on. 45 | 46 | 47 | Up Next: [Updating and `componentWillReceiveProps()`](update/component_will_receive_props.md) 48 | 49 | --- 50 | 51 | [^1] With Component state, we consider this internal functionality. In theory, we can access and even edit state outside of the instance but this is an anti-pattern. Accessing a Component's state from outside injects a lot of fragility into the system (pathing dependency, changing of internal values, etc.). Only a Component instance should `setState()` on itself. 52 | 53 | [^2] Even though moving `props` to `state` [is considered an anti-pattern](https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html) there are a few use cases. The most common is having a `defaultValue` prop that becomes the internal `value` in state. We see this pattern with most Form elements in React; although there is a strong movement to get away from this and work with only [Controlled Components](https://facebook.github.io/react/docs/forms.html#controlled-components). 54 | 55 | [^3] The React code comments recommend that *"... You should treat `this.state` as immutable. There is no guarantee that `this.state` will be immediately updated, so accessing `this.state` after calling [the setState] method may return the old value."* 56 | 57 | [^4] React internal method `enqueueSetState()` to be exact. 58 | 59 | -------------------------------------------------------------------------------- /patterns/the_evolution_of_a_list_component.md: -------------------------------------------------------------------------------- 1 | # The Evolution of a List Component 2 | Lists are everywhere in applications today. The list is crucial to Social Media UIs, such as Facebook, Twitter, Reddit, Instagram, etc. The current demo app trend of Todos are all about displaying a list of items. The lowly HTML drop-down displays a list of selectable options. It's so common, most of us take lists for granted. 3 | 4 | When we start building our application, how should we approach creating reusable Components? Let's walk through a possible progression of a list feature. 5 | 6 | ## The first pass 7 | Typically, the first approach is to build a React component that renders the UI to the specific layout and data needs. For our example, we are building a list of customer profiles. The first design round requires the profile to have an avatar/picture and descriptive text. 8 | 9 | ** UI Wireframe #1** 10 | 11 | ![A simple profile](react-indepth-avatar-list.png) 12 | 13 | The first step would be to create a Component that takes an Array of Objects, which has an image path and the description text. Our Component will loop over this Array and render out each element, using `
  • ` items. 14 | 15 | ```javascript 16 | import React from 'react'; 17 | 18 | class List extends React.Component { 19 | renderProfiles () { 20 | return this.props.profile.map( (profile) => { 21 | return ( 22 |
  • 23 | 24 |
    25 | { profile.description } 26 |
    27 |
  • 28 | ); 29 | }); 30 | } 31 | 32 | render() { 33 | return (
      { this.renderProfiles() }
    ); 34 | } 35 | } 36 | 37 | List.defaultProps = { profile: [] }; 38 | export default List; 39 | ``` 40 | 41 | We would then apply styling to the `
      `, `
    • ` and `
      ` elements to meet our design needs. This Component is a simple way of rendering out our content. It meets our design needs but isn't reusable. 42 | 43 | ## Requirements change 44 | As with any project, needs change. For our example, the users now want to list more details about each customer. The design team comes up with a new layout and we now have to support optional fields. 45 | 46 | ** UI Wireframe #2** 47 | 48 | ![Optional Details](react-indepth-details-list.png) 49 | 50 | With this new design we now need to do our first bit of Component refactoring. To support the new optional detail fields, we need to add logic to our Profile rendering. A good development practice is to keep our React Components as compartmentalized as possible. This enables multiple benefits. 51 | 52 | First, it helps reduce cognitive load. Having smaller, single focused Components means they are easier to read and understand the intention. A common experience we have all had as developers is returning to our own code six or more months later. Because we wrote it, we *should* understand it, but often it takes a bit of time to put ourselves back into mindset of what the code is solving. If the Component has hundreds of lines of logic, it will take that much more time to grok what the intention is. Even harder (and time consuming) is doing this with another developer's work. 53 | 54 | One of the beautiful features of React is that we can (and should) break our Components into small bite-sized chunks. Because it is so easy in React, this helps us make our code easier to understand. At the same time, this leads to the second benefit: faster reusability. 55 | 56 | If we break out a Component to a single task, such as rendering a single profile, we now have the potential to reuse it. It is possible that elsewhere in the app we need to show a profile. With our current implementation, this is not easily done. This is because the rendering of the profile details is handled internally by the List component. Let's break the profile details out into a new Component and refactor our List a bit. 57 | 58 | ## Creating a Profile Component 59 | The first step is to move the render code from the List into it's own Component. 60 | 61 | **Profile.js** 62 | ```javascript 63 | import React from 'react'; 64 | 65 | export default class Profile extends React.Component { 66 | renderDetails(key, label){ 67 | if (this.props[key]) { 68 | return (
      { label } { this.props[key] }
      ); 69 | } 70 | } 71 | 72 | render() { 73 | return ( 74 |
    • 75 | 76 |
      77 | { this.props.description } 78 |
      79 | { this.renderDetails('email', 'Email:') } 80 | { this.renderDetails('twitter', 'Twitter:') } 81 | { this.renderDetails('phone', 'Phone:') } 82 |
    • 83 | ); 84 | } 85 | } 86 | ``` 87 | 88 | Here we have broken out the optional details rendering into a new Component called `Profile`. Profile's job is to render out the base layout and then render out our optional details, depending on if they are defined or not[^1]. We can then update our List code: 89 | 90 | **List.js** 91 | 92 | ```javascript 93 | import React from 'react'; 94 | import Profile from './Profile'; 95 | 96 | class List extends React.Component { 97 | render() { 98 | return ( 99 |
        100 | { this.props.profile.map( (profile) => ) } 101 |
      102 | ); 103 | } 104 | } 105 | 106 | List.defaultProps = { profile: [] }; 107 | export default List; 108 | ``` 109 | 110 | Now our List maps the profile data and sends it to the `Profile` Component for rendering. By isolating the rendering of the profile to a single component we have a clear [separation of concerns (SoC)](https://en.wikipedia.org/wiki/Separation_of_concerns). Not only do we get the benefit of SoC, we also make each Component a lot easier to understand. When we have to return to this code six months later, it will be a lot faster to get caught back up. 111 | 112 | ***Up Next***: [Rendering Different Content](rendering_different_content.md) 113 | 114 | --- 115 | 116 | [^1] Following this pattern we could go even further if so desired. We could break out each Profile detail into its own Component. Yet, that maybe going too far down the granularity rabbit hole. Once again, over-architecture is a slippery slope and having to make a judgment call is part of the process. 117 | 118 | -------------------------------------------------------------------------------- /life_cycle/birth/post_mount_with_component_did_mount.md: -------------------------------------------------------------------------------- 1 | # Post-mount with `componentDidMount()` 2 | The last step in the Birth/Mount life cycle phase is our post-mount access via `componentDidMount()`. This method is called once all our children Elements and our Component instances are mounted onto the Native UI. When this method is called we now have access to the Native UI (DOM, UIView, etc.), access to our children `refs` and the ability to *potentially* trigger a new render pass. 3 | 4 | ## Understanding call order 5 | Similar to `componentWillMount()`, `componentDidMount()` is only called one time. Unlike our other Birth/Mount methods, where we start at the top and work down, `componentDidMount()` works from the bottom up. Let's consider the following Component/Element Tree again: 6 | 7 | ![React Element Tree](react-element-tree.png) 8 | 9 | When we begin the Birth phase, we process `render()` in this order: 10 | 11 | ``` 12 | A -> A.0 -> A.0.0 -> A.0.1 -> A.1 -> A.2. 13 | ``` 14 | 15 | With `componentDidMount()` we start at the end and work our way back. 16 | 17 | ``` 18 | A.2 -> A.1 -> A.0.1 -> A.0.0 -> A.0 -> A 19 | ``` 20 | 21 | By walking backwards, we know that every child has mounted and also run its own `componentDidMount()`. This guarantees the parent can access the Native UI elements for itself and its children. 22 | 23 | Let's consider the following three components and their call order. 24 | 25 | **GrandChild.js** 26 | ```javascript 27 | /** 28 | * GrandChild 29 | * It logs the componentDidMount() and has a public method called value. 30 | */ 31 | import React from 'react'; 32 | import ReactDOM from 'react-dom'; 33 | 34 | export default class GrandChild extends React.Component { 35 | 36 | componentDidMount() { 37 | console.log('GrandChild did mount.'); 38 | } 39 | 40 | value() { 41 | return ReactDOM.findDOMNode(this.refs.input).value; 42 | } 43 | 44 | render() { 45 | return ( 46 |
      47 | GrandChild 48 | 49 |
      50 | ); 51 | } 52 | } 53 | ``` 54 | 55 | **Child.js** 56 | ```javascript 57 | /* 58 | * Child 59 | * It logs the componentDidMount() and has a public method called value, 60 | * which returns the GrandChild value. 61 | */ 62 | import React from 'react'; 63 | import GrandChild from './GrandChild'; 64 | 65 | export default class Child extends React.Component { 66 | 67 | componentDidMount() { 68 | console.log('Child did mount.'); 69 | } 70 | 71 | value() { 72 | return this.refs.grandChild.value(); 73 | } 74 | 75 | render() { 76 | return ( 77 |
      78 | Child 79 | 80 |
      81 | ); 82 | } 83 | } 84 | ``` 85 | 86 | **Parent.js** 87 | ```javascript 88 | /* 89 | * Parent 90 | * It logs the componentDidMount() and then logs the child value() 91 | * method. 92 | */ 93 | import React from 'react'; 94 | import Child from './Child'; 95 | 96 | export default class Parent extends React.Component { 97 | 98 | componentDidMount() { 99 | console.log('Parent did mount.'); 100 | console.log('Child value:', this.refs.child.value()); 101 | } 102 | 103 | render() { 104 | return ( 105 |
      106 | Parent 107 | 108 |
      109 | ); 110 | } 111 | } 112 | ``` 113 | 114 | When we mount `` in our application we get the following in the browser console: 115 | 116 | ```console 117 | GrandChild did mount. 118 | Child did mount. 119 | Parent did mount. 120 | Child value: foo 121 | ``` 122 | 123 | As you can see, the GrandChild's `componentDidMount()` was called first, followed by Child and then Parent. Because we are now mounted on the DOM and our children are created, the Parent can access its `refs` and the GrandChild can access its own DOM nodes. 124 | 125 | ## Useful Tasks 126 | The `componentDidMount()` method can be a helpful heavy lifter for our Components. One of the most common tasks is interacting with the Native UI. Unlike `componentWillMount()` or `render()` we can now fully interact with the Native stack. 127 | 128 | For example, we may need to make changes to our current state based on how the Native UI laid out our content. We may need to figure out the current width/height of our children or our own instance. This is especially helpful in the browser where CSS layout drives a lot of our DOM calculations. 129 | 130 | Another useful task is setting up 3rd party UIs. For example, if we wanted to use a library like [C3.js](http://c3js.org/) or the [Date Range Picker](http://www.daterangepicker.com/), this is where we would initialize our UI libraries. 131 | 132 | **Chart.js** 133 | 134 | ```javascript 135 | import React from 'react'; 136 | import ReactDOM from 'react-dom'; 137 | import c3 from 'c3'; 138 | 139 | export default class Chart extends React.Component { 140 | 141 | componentDidMount() { 142 | this.chart = c3.generate({ 143 | bindto: ReactDOM.findDOMNode(this.refs.chart), 144 | data: { 145 | columns: [ 146 | ['data1', 30, 200, 100, 400, 150, 250], 147 | ['data2', 50, 20, 10, 40, 15, 25] 148 | ] 149 | } 150 | }); 151 | } 152 | 153 | render() { 154 | return ( 155 |
      156 | ); 157 | } 158 | } 159 | ``` 160 | 161 | In the above example, we leverage `componentDidMount()` to generate our chart, bind it to the DOM using `refs` and then pass in data. 162 | 163 | When integrating 3rd party libraries, we often need to bind to events, such as the user interacting with the Chart. This is where we would set up our listeners post-library initialization. We can also add more global listeners here, if we did not want to setup the listeners in the `componentWillMount()` call. 164 | 165 | ## Starting another render pass [^1] 166 | There are some unique situations where we may have a second render immediately after Birth/Mount. This is not a common situation and generally occurs when we have to change our current state based on the Native UI Layout. This could be calculating dynamic row height or column widths in a data table. It could be having to re-position the component's children based on how they are sized the first time. 167 | 168 | If you require this kind of functionality, you have the ability to call `this.setState()` or `forceUpdate()` in your `componentDidMount()`. If you change state or force an update (more on this feature later), your Component will begin another render pass and enter the [Growth/Update Phase](../growth_update_indepth.md). Because `componentDidMount()` is called only once, we don't have to worry about this method causing an infinite loop. But, this process can lead to issues down the road if you do not take the time to walk through all the potential ramifications of multiple renders. 169 | 170 | ***Up Next:*** [Growth/Update Phase In-Depth](../growth_update_indepth.md) 171 | 172 | --- 173 | 174 | [^1] Multiple render passes opens the door for serious performance issues. Proceed with extreme caution! 175 | 176 | -------------------------------------------------------------------------------- /life_cycle/birth/initialization_and_construction.md: -------------------------------------------------------------------------------- 1 | # Initialization & Construction 2 | During the initialization of the Component from the Element, the `props` and `state` are defined. How these values are defined depends on if you are using `React.createClass()` or `extend React.Component`. Let's first look at `props` and then we will examine `state`. 3 | 4 | ## Default Props 5 | As we mentioned earlier, the Element instance contains the current `props` that are being passed to the Component instance. Most of the time, all the available `props` on the Component are not required. Yet, some times we do need to have values for all the `props` for our Component to render correctly. 6 | 7 | For example, we have a simple component that renders a name and age. 8 | 9 | ```javascript 10 | import React from 'react'; 11 | 12 | export default class Person extends React.Component { 13 | render() { 14 | return ( 15 |
      { this.props.name } (age: { this.props.age })
      16 | ); 17 | } 18 | } 19 | ``` 20 | 21 | 22 | In our case, we expect two props to be passed in: `name` and `age`. If we want to make `age` optional and default to the text 'unknown' we can take advantage of React's default props. 23 | 24 | **For ES6 Class** 25 | ```javascript 26 | import React from 'react'; 27 | 28 | class Person extends React.Component { 29 | render() { 30 | return ( 31 |
      { this.props.name } (age: { this.props.age })
      32 | ); 33 | } 34 | } 35 | 36 | Person.defaultProps = { age: 'unknown' }; 37 | 38 | export default Person; 39 | ``` 40 | 41 | **For createClass (ES6/ES5/CoffeeScript, etc.)** 42 | 43 | ```javascript 44 | var Person = React.createClass({ 45 | getDefaultProps: function() { 46 | return ({ age: 'unknown' }); 47 | }, 48 | 49 | render: function() { 50 | return ( 51 |
      { this.props.name } (age: { this.props.age })
      52 | ); 53 | } 54 | }); 55 | ``` 56 | 57 | The result of either process is the same. If we create a new instance without setting the age prop ex: ``, the component will render `
      Bill (age: unknown)
      `. 58 | 59 | React handles default props by merging the passed props object and the default props object. This process is similar to [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) or the Lodash/Underscore [`_.assign()`](https://lodash.com/docs#assign) method. The default props object is the target object and the passed props is the source: 60 | 61 | ```javascript 62 | // React library code to extract defaultProps to the Constructor 63 | if (Constructor.getDefaultProps) { 64 | Constructor.defaultProps = Constructor.getDefaultProps(); 65 | } 66 | 67 | // psuedo code (as an example) 68 | this.props = Object.assign(Constructor.defaultProps, elementInstance.props); 69 | ``` 70 | 71 | In the React code snippet, React checks the underlying Class instance to see if it defines `getDefaultProps()` and uses this to set the values. When using ES6 classes we just define it on the class itself. Any property defined on the `passedProps` value is applied/overridden to the property in the default props object. 72 | 73 | ### `null` vs. `undefined` props 74 | When using default props, it is important to understand how the React merge process works. Often, we are generating props dynamically based on application state ([Flux](https://facebook.github.io/flux/), [Redux](http://redux.js.org/), [Mobx](https://github.com/mobxjs/mobx), etc.). This means that we can sometimes generate `null` values and pass this as the prop. 75 | 76 | When assigning default props, the React object merge code sees `null` as a defined value. 77 | 78 | ```javascript 79 | 80 | ``` 81 | 82 | Because `null` is a defined value our Component would render this as `
      Bob (age:)
      ` instead of rendering *unknown*. But, if we pass in `undefined` instead of `null`, React treats this as undefined (well yeah, obviously) and we would render *unknown* as expected. 83 | 84 | Keep this in mind when defining default props, because tracing down a `null` value can be tricky in larger application. 85 | 86 | ## Initial State 87 | Once the final props are defined (passed w/ defaults), the Component instance configures the initial `state`. This process occurs in the construction of the instance itself. Unlike props, the Component state is an internal object that is not defined by outside values. 88 | 89 | To define the initial `state` depends on how you declare your Component. For ES6 we declare the state in the constructor. Just like `defaultProps`, the initial state takes an object. 90 | 91 | **For ES6 Class** 92 | ```javascript 93 | import React from 'react'; 94 | 95 | class Person extends React.Component { 96 | constructor(props) { 97 | super(props); 98 | this.state = { count: 0 }; 99 | } 100 | 101 | render() { 102 | return ( 103 |
      { this.props.name } (age: { this.props.age })
      104 | ); 105 | } 106 | } 107 | 108 | Person.defaultProps = { age: 'unknown' }; 109 | 110 | export default Person; 111 | ``` 112 | 113 | For `React.createClass` Components, there is a helper method called `getInitialState()` which returns the state object. This method is called during setup to set the state on the instance. 114 | 115 | **For createClass (ES6/ES5/CoffeeScript, etc.)** 116 | 117 | ```javascript 118 | var Person = React.createClass({ 119 | getDefaultProps: function() { 120 | return ({ age: 'unknown' }); 121 | }, 122 | 123 | getInitialState: function() { 124 | return ({ count: 0 }); 125 | }, 126 | 127 | render: function() { 128 | return ( 129 |
      { this.props.name } (age: { this.props.age })
      130 | ); 131 | } 132 | }); 133 | ``` 134 | 135 | ### State defaults 136 | It is important to keep in mind that if we do not define a state in the constructor/getInitialState then the state will be `undefined`. Because the state is `undefined` and not an empty Object (`{}`), if you try to query the state later on this will be an issue. 137 | 138 | In general, we want to set a default value for all our state properties. There are some edge cases where the initial value for the state property may be `null` or `undefined`. If this state happens to be only state property, it may be tempting to skip setting a default state. But, if our code tries to access the property you will get an error. 139 | 140 | ```javascript 141 | class Person extends React.Component { 142 | render() { 143 | // This statement will throw an error 144 | console.log(this.state.foo); 145 | return ( 146 |
      { this.props.name } (age: { this.props.age })
      147 | ); 148 | } 149 | } 150 | ``` 151 | 152 | The log statement fails because `this.state` is undefined. When we try to access `foo` we will get a *TypeError: Cannot read property 'foo' of null*. To solve this we can either set the default state to `{}` or, to have a clearer intention, set it to `{ foo: null }`. 153 | 154 | ***Next Up:*** [Pre-mounting with `componentWillMount()`](premounting_with_componentwillmount.md) 155 | -------------------------------------------------------------------------------- /patterns/higher_order_components.md: -------------------------------------------------------------------------------- 1 | # Higher Order Components 2 | The last Component composition pattern we will examine in this section is *Higher Order Components* (HOC). As [Dan Abramov discusses](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750#.b74nxbqew), Higher Order Components were first proposed by [Sebastian Markbåge](https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775) in a gist. The core idea of HOC is to define a function, which you pass one or more Components to. This function generates and returns a new Component, which is a wrapper around the passed in Component(s). 3 | 4 | The need for HOC came about with React's move to support ES6 classes and the lack of mixin support with the new JavaScript Class syntax. To handle this change, a new pattern needed to be defined to replace mixins. Typically, mixins add/override functionality around the [Component Life Cycle](../life_cycle/introduction.md) and enable sharing reusable code in a elegant way. Without mixin support in ES6, the HOC pattern is required. 5 | 6 | ### A form group example 7 | For our HOC example, we will create a function for wrapping a Component in a custom form group with an optional `