Skip to content

Commit ca71647

Browse files
Merge pull request #3 from ui-router/react-hellogalaxy
add HelloGalaxy react tutorial
2 parents 4ab6d77 + 4ed1e5d commit ca71647

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

_tutorial_react/hellogalaxy.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
title: "UI-Router for React - Hello Galaxy!"
3+
excerpt: "Learn about Nested States and Nested Views"
4+
---
5+
{% include toc icon="columns" title="Hello Galaxy!" %}
6+
7+
In the ["Hello Solar System!"](hellosolarsystem) app, we created a list/detail interface.
8+
We showed a list of `people` and allowed the user to drill down to view a single `person`'s details.
9+
We implemented both the `people` and `person` states as siblings (peers to each other).
10+
When `people` was active, `person` could not be active, and vice versa.
11+
12+
In this section, we will create a parent-child state relationship by nesting the `person` state _inside_ the `people` state.
13+
We will also nest their views, showing `person` details inside the `people` component.
14+
15+
## Live demo
16+
17+
As usual, let's first look at a live demo of the finished "Hello Galaxy" app.
18+
19+
Click the "People" tab, then click on a person.
20+
21+
<iframe style="width: 100%; height: 500px;"
22+
src="//embed.plnkr.co/NfIhgwegG7YF0kfbBewj/?show=preview"
23+
frameborder="1" allowfullscren="allowfullscren"></iframe>
24+
25+
When you switch from one state to the another, it is called a Transition.
26+
On the bottom of the plunker, the [UI-Router Transition Visualizer](https://github.com/ui-router/visualizer)
27+
shows each transition visually, and provides transition details when hovered and/or clicked.
28+
{: .notice--info}
29+
30+
# Nesting States
31+
32+
UI-Router states form a tree, starting from a single root state.
33+
The root state is implicit and has no name.
34+
The top-level application states (such as `about` and `people`) are children of the implicit root state.
35+
36+
The "Hello Solar System" app had four top-level states, while the
37+
"Hello Galaxy" app has three top-level states and one nested state.
38+
39+
<figure class="half">
40+
<img src="/assets/tutorial/hellosolarsystem.png">
41+
<img src="/assets/tutorial/hellogalaxy.png">
42+
</figure>
43+
44+
The `person` state is now a child of the `people` state.
45+
{: .notice--info}
46+
47+
The new `person` state definition:
48+
49+
```js
50+
const person = {
51+
name: 'people.person',
52+
url: '/:personId',
53+
component: Person,
54+
resolve: [{
55+
token: 'person',
56+
deps: ['$transition$', 'people'],
57+
resolveFn: (trans, people) =>
58+
people.find(person => person.id === trans.params().personId)
59+
}]
60+
}
61+
```
62+
63+
64+
65+
![Changes to Person state definition](/assets/tutorial/ss-to-galaxy-diff-react.png)
66+
We made some changes to the `person` state properties to make it a nested state... let's go over each change.
67+
68+
69+
70+
## State name
71+
72+
We changed the `name:` from `person` to `people.person`.
73+
74+
When naming a state, prepending another state's name (and a dot) creates a parent/child relationship.
75+
In this case, the `people.person` state is a child of the `people` state.
76+
77+
Another way to create a parent/child relationship is with the `parent:` property of a state definition.
78+
{: .notice--info}
79+
80+
## URL
81+
82+
We changed the `url:` from `/people/{personId}` to the url fragment `/{personId}`.
83+
84+
The child state's `url:` property is a url fragment (a partial url).
85+
The full url for a child state is built by appending the child state's url fragment to the parent state's url.
86+
87+
The url for the parent state (`people`) is still `/people`.
88+
Appending `/{personId}` to `/people` results in `/people/{personId}` (which is the same as our previous `person` url).
89+
90+
The router will map a browser url of `/people` to the `people` state.
91+
It will map a browser url of `/people/123` to the `person` state, with a `peopleId` parameter value of "123".
92+
93+
## Resolve
94+
95+
We changed the `resolve:` to use the data from the parent resolve, instead of fetching it from the server.
96+
97+
As before, when you click the "People" tab the router fetches the `people` resolve from the server API,
98+
then activates the `people` state and renders the view.
99+
100+
With our new nested state setup, the `person` resolve is a bit different.
101+
When we click a specific person, the router still invokes the `person` resolve before activating the `person` state.
102+
However, this resolve is a bit different.
103+
Instead of fetching the person from the server, the `person` resolve injects the parent state's `people` resolve.
104+
Since the list of people is already loaded in the parent resolve, no additional fetching occurs.
105+
106+
A resolve function may inject the results of other resolves from ancestor states, or from other resolves on the same state.
107+
{: .notice--info}
108+
109+
110+
## Views
111+
112+
The view for `person` hasn't changed.
113+
It is still a component named `Person`, which has a `resolves` attribute in its `props`.
114+
The resolve data named `person` is still passed via the component props.
115+
116+
However, the parent state's `People` component has changed a bit.
117+
118+
{% raw %}
119+
```js
120+
render () {
121+
let {people} = this.props.resolves;
122+
123+
let list = people.map((person, index) => (
124+
<li key={index}>
125+
<UISref to=".person" params={{personId:person.id}}>
126+
<a>{person.name}</a>
127+
</UISref>
128+
</li>
129+
));
130+
131+
return (
132+
<div className={this.props.className}>
133+
<div className="flex-h">
134+
<div className="people">
135+
<h3>Some people:</h3>
136+
<ul>
137+
{list}
138+
</ul>
139+
</div>
140+
<UIView className="debug__UIView" />
141+
</div>
142+
</div>
143+
);
144+
}
145+
```
146+
{% endraw %}
147+
148+
We've added some container `div`s for layout and embedded a nested `<UIView>` viewport.
149+
When a child state of `people` is activated, its view is put into the viewport.
150+
We also added some styling to create a side by side layout, so the nested viewport appears on the right.
151+
152+
153+
<video controls="controls" autoplay loop>
154+
<source src="/assets/tutorial/nested view.mov.mp4" type="video/mp4">
155+
<source src="/assets/tutorial/nested view.mov.webm" type="video/webm">
156+
</video>
157+
158+
Note the nested `<UIView>` when "People" is activated.
159+
That `<UIView>` is filled with the `person` view when the `person` state is active.
160+
{: .notice--info}
161+
162+
## Links
163+
164+
We also changed the `UISref` links in the `people` state which drill down to a specific person.
165+
{% raw %}
166+
Previously, these links were `<UISref to="person" params={{personId:person.id}}><a>{person.name}</a></UISref>`.
167+
Since the `person` state is now named `people.person`, we changed the links to `<UISref to="people.person" params={{personId:person.id}}><a>{person.name}</a></UISref>`.
168+
169+
We could also have used relative addressing: `<UISref to=".person" params={{personId:person.id}}><a>{person.name}</a></UISref>`.
170+
Since the `UISref` was created in the `people` state's view and it relatively targets `.person`, the final target state is `people.person`.
171+
{: .notice--info}
172+
{% endraw %}
173+
174+
# Transitions
175+
176+
TODO
71.5 KB
Loading

0 commit comments

Comments
 (0)