|
| 1 | +# Component Lifecycle when Routing |
| 2 | + |
| 3 | +Its important to understand which lifecycle hooks are going to be called |
| 4 | +on your route components to implement lots of different functionality in |
| 5 | +your app. The most common thing is fetching data. |
| 6 | + |
| 7 | +There is no difference in the lifecycle of a componet in the router as |
| 8 | +just React itself. Let's peel away the idea of routes, and just think |
| 9 | +about the components being rendered at different urls. |
| 10 | + |
| 11 | +Consider this route config: |
| 12 | + |
| 13 | +```js |
| 14 | +<Route path="/" component={App}> |
| 15 | + <IndexRoute component={Home}/> |
| 16 | + <Route path="invoices/:invoiceId" component={Invoice}/> |
| 17 | + <Route path="accounts/:accountId" component={Account}/> |
| 18 | +</Route> |
| 19 | +``` |
| 20 | + |
| 21 | +## Lifecycle hooks when routing |
| 22 | + |
| 23 | +1. Lets say the user enters the app at `/`. |
| 24 | + |
| 25 | +| Component | Lifecycle Hooks called | |
| 26 | +-------------------------------------- |
| 27 | +| App | componentDidMount | |
| 28 | +| Home | componentDidMount | |
| 29 | +| Invoice | N/A | |
| 30 | +| Account | N/A | |
| 31 | + |
| 32 | +2. Now they navigate from `/` to `/invoice/123` |
| 33 | + |
| 34 | +| Component | Lifecycle Hooks called | |
| 35 | +-------------------------------------- |
| 36 | +| App | componentWillReceiveProps, componentDidUpdate | |
| 37 | +| Home | componentWillUnmount | |
| 38 | +| Invoice | componentDidMount | |
| 39 | +| Account | N/A | |
| 40 | + |
| 41 | +- `App` gets `componentWillReceiveProps` and `componentDidUpdate` because it |
| 42 | +stayed rendered but just received new props from the router (like |
| 43 | +`children`, `params`, `location`, etc.) |
| 44 | +- `Home` is no longer rendered, so it gets unmounted. |
| 45 | +- `Invoice` is mounted for the first time. |
| 46 | + |
| 47 | + |
| 48 | +3. Now they navigate from `/invoice/123` to `/invoice/789` |
| 49 | + |
| 50 | +| Component | Lifecycle Hooks called | |
| 51 | +-------------------------------------- |
| 52 | +| App | componentWillReceiveProps, componentDidUpdate | |
| 53 | +| Home | N/A | |
| 54 | +| Invoice | componentWillReceiveProps, componentDidUpdate | |
| 55 | +| Account | N/A | |
| 56 | + |
| 57 | +All the components that were mounted before, are still mounted, they |
| 58 | +just receive new props from the router. |
| 59 | + |
| 60 | +4. Now they navigate from `/invoice/789` to `/accounts/123` |
| 61 | + |
| 62 | +| Component | Lifecycle Hooks called | |
| 63 | +-------------------------------------- |
| 64 | +| App | componentWillReceiveProps, componentDidUpdate | |
| 65 | +| Home | N/A | |
| 66 | +| Invoice | componentWillUnmount | |
| 67 | +| Account | componentDidMount | |
| 68 | + |
| 69 | +## Fetching Data |
| 70 | + |
| 71 | +While there are other ways to fetch data with the router, the simplest |
| 72 | +way is to simply use the lifecycle hooks of your components and keep |
| 73 | +that data in state. Now that we understand the lifecycle of components |
| 74 | +when changing routes, we can implement simple data fetching inside of |
| 75 | +`Invoice`. |
| 76 | + |
| 77 | +```js |
| 78 | +let Invoice = React.createClass({ |
| 79 | + |
| 80 | + getInitialState () { |
| 81 | + return { |
| 82 | + invoice: null |
| 83 | + } |
| 84 | + }, |
| 85 | + |
| 86 | + componentDidMount () { |
| 87 | + // fetch data initially in scenario 2 from above |
| 88 | + this.fetchInvoice() |
| 89 | + }, |
| 90 | + |
| 91 | + componentDidUpdate (prevProps) { |
| 92 | + // respond to parameter change in scenario 3 |
| 93 | + let oldId = prevProps.params.invoiceId |
| 94 | + let newId = this.props.params.invoiceId |
| 95 | + if (newId !== oldId) |
| 96 | + this.fetchInvoice() |
| 97 | + }, |
| 98 | + |
| 99 | + componentWillUnmount () { |
| 100 | + // allows us to ignore an inflight request in scenario 4 |
| 101 | + this.ignoreLastFetch = true |
| 102 | + }, |
| 103 | + |
| 104 | + fetchInvoice () { |
| 105 | + let url = `/api/invoices/${this.props.params.invoiceId}` |
| 106 | + this.request = fetch(url, (err, data) => { |
| 107 | + if (!this.ignoreLastFetch) |
| 108 | + this.setState({ invoice: data.invoice }) |
| 109 | + }) |
| 110 | + }, |
| 111 | + |
| 112 | + render () { |
| 113 | + return <InvoiceView invoice={this.state.invoice}/> |
| 114 | + } |
| 115 | + |
| 116 | +}) |
| 117 | +``` |
| 118 | + |
0 commit comments