`. If you were to replace `View` with `div` and `Text` with `span`, this would look almost regular HTML (and exactly the same as React on the web):
133 | ```html
134 |
135 | Open up App.js to start working on your app!
136 | Changes you make will automatically reload.
137 | Shake your phone to open the developer menu.
138 |
139 | ```
140 |
141 | Because React Native exists for creating native apps, web primitives like div and span aren't available to us. Instead, on line 2 we imported some of the React Native primitives: View, Text, etc. There are counterparts for most important web primitives, as well as hundreds of others, either included in React Native, included in Expo, or installable via NPM. We will look at these later.
142 |
143 | #### Styles
144 |
145 | The last section in the file are the styles. If JSX reminded you of HTML, the React Native style system should remind you of CSS.
146 | ```js
147 | const styles = StyleSheet.create({
148 | container: {
149 | flex: 1,
150 | backgroundColor: '#fff',
151 | alignItems: 'center',
152 | justifyContent: 'center',
153 | },
154 | });
155 | ```
156 |
157 | The same in CSS would look something like this:
158 | ```CSS
159 | .container {
160 | display: flex;
161 | flex: 1;
162 | background-color: #fff;
163 | align-items: center;
164 | justify-content: center;
165 | }
166 | ```
167 |
168 | In fact, React Native implements a subset of CSS in JavaScript, including the [Flexbox](http://www.reactnativeexpress.com/flexbox) layout system we'll use to arrange our app components on the screen. The `display: flex` line from the CSS translation is not necessary in React Native, because all components "flex" by default.
169 |
170 | Now, finally, let's code!
171 |
172 | # Let's code!
173 |
174 | ## Step 1. Connect to chat server
175 | In order to be able to chat with other users, we'll need a server. Happily, we have one available, and we can install a client library from NPM! Run the following in the project directory:
176 |
177 | ```sh
178 | npm install --save react-native-training-chat-server
179 | ```
180 |
181 | Then, in **App.js** add the following lines after the react-native imports:
182 |
183 | ```js
184 | import {send, subscribe} from 'react-native-training-chat-server';
185 |
186 | const NAME = 'Your Name';
187 | const CHANNEL = 'Reactivate';
188 | ```
189 |
190 | Replace "Your name" with ... well, your name 😂! The channel can be any alphanumeric string - feel free to set up your own secret channel or use the default "Reactivate" to participate with everyone else. You'll now have access to two functions, `send` and `subscribe` that we'll use to send and receive messages.
191 |
192 | ## Step 2. Get messages
193 |
194 | Next, we'll need to subscribe to our channel when our app starts. Add the following lines immediately below the component declaration:
195 | ```js
196 | export default class App extends React.Component {
197 | //new lines below...
198 | state = {
199 | messages: [],
200 | };
201 |
202 | componentDidMount() {
203 | subscribe(CHANNEL, messages => {
204 | this.setState({messages});
205 | });
206 | }
207 | //...end new lines
208 | }
209 | ```
210 | It's just a few of lines of code, but there is a lot to unpack here.
211 |
212 | 1. First, we declare our [state](https://facebook.github.io/react-native/docs/state.html) - this is where React components can store their data and other dynamically changing state. In this case we initialize an empty state with an empty `messages` array.
213 | 2. Then, we declare a method named (exactly) `componentDidMount`, one of the special [Lifecycle methods](https://facebook.github.io/react/docs/react-component.html#the-component-lifecycle) on every React component that will be called at different phases of the component's lifetime. This one will be called just after the component has "mounted", or in our case, when the App has first started.
214 | 3. Inside the lifecycle method, we `subscribe` to our chat server with a channel name and a callback function. The callback will be called every time new messages arrive.
215 | 4. In the callback, we call another special React method, `this.setState`. This method is responsible for updating the initial state we declared above. After you call `setState`, the component will automatically re-render and update the UI of our application!
216 |
217 | You won't yet see any changes on the screen, because we haven't rendered our messages. We'll get to that next, but if you want to verify the subscription works, you can add a `console.log(messages)` into the callback. To access the debugger menu, shake your device and choose "Debug JS Remotely" option to view the log in Chrome Dev Tools. If running on simulator, see the [Debugging](https://facebook.github.io/react-native/docs/debugging.html) guide in React Native docs.
218 |
219 | ## Step 3. Render messages
220 |
221 | Next, let's put some messages on the screen! We'll want to render the messages as a list, so we'll need to start by importing the [FlatList](https://facebook.github.io/react-native/docs/flatlist.html) component from the react-native package on the top of the file:
222 | ```diff
223 | import React from 'react';
224 | - import { StyleSheet, Text, View } from 'react-native';
225 | + import { StyleSheet, Text, View, FlatList } from 'react-native';
226 | ```
227 |
228 | Then, we can replace the placeholder text in our `render` method with a FlatList:
229 | ```diff
230 | render() {
231 | return (
232 |
233 | - Open up App.js to start working on your app!
234 | - Changes you make will automatically reload.
235 | - Shake your phone to open the developer menu.
236 | +
241 |
242 | );
243 | }
244 | ```
245 |
246 | We pass FlatList attributes, or [Props](https://facebook.github.io/react-native/docs/props.html). Props is how React components can pass data to each other. In this case, the props are:
247 |
248 | 1. `data={this.state.messages}` - FlatList expects an array of "data" to render, so we give it a list of messages we fetched earlier.
249 | 2. `renderItem={this.renderItem}` - FlatList also needs a callback it can call for each item in the `data` array to render the corresponding row. Here we pass it a method `this.renderItem`.
250 | 3. `inverted` - This prop will render the list in reverse order, so that latest messages are always anchored to the bottom of the list.
251 |
252 | The renderItem method isn't one of the special lifecycle methods - it's just a plain old method on the class. In fact, it doesn't even exist yet, so let's create it now. Place the renderItem method immediately *above* your component's `render` method:
253 |
254 | ```js
255 | renderItem({item}) {
256 | return (
257 |
258 | {item.sender}
259 | {item.message}
260 |
261 | );
262 | }
263 | ```
264 |
265 | If you are using a Channel that someone has posted any messages in it, you should now see them on the screen! They'll look a bit ugly, and a bit squashed, though. That's because we haven't yet added any styles. Let's do that next.
266 |
267 | ## Step 4. Styling the list
268 |
269 | In the `renderItem` method, you see references to styles like `styles.row`, `styles.sender`, `styles.message`. These styles can be defined in the bottom of the file, replacing the existing StyleSheet:
270 |
271 | ```js
272 | const styles = StyleSheet.create({
273 | container: {
274 | flex: 1,
275 | backgroundColor: '#fff',
276 | },
277 | row: {
278 | padding: 20,
279 | borderBottomWidth: 1,
280 | borderBottomColor: '#eee',
281 | },
282 | message: {
283 | fontSize: 18,
284 | },
285 | sender: {
286 | fontWeight: 'bold',
287 | paddingRight: 10,
288 | },
289 | });
290 | ```
291 | Feel free to play around with the styles and make it look different. The style names and values usually match how CSS works on the web, except names are written using camel casing, e.g `backgroundColor` rather than `background-color`.
292 |
293 | ## Checkpoint
294 |
295 | At this point, you should see a styled list of messages. There is no one right way to achieve this, but this is how my App.js looks like:
296 |
297 |
298 | App.js (Click to expand)
299 |
300 | ```js
301 | import React from 'react';
302 | import {StyleSheet, Text, View, FlatList} from 'react-native';
303 | import {send, subscribe} from 'react-native-training-chat-server';
304 |
305 | const NAME = 'Your name';
306 | const CHANNEL = 'Reactivate';
307 |
308 | export default class App extends React.Component {
309 | state = {
310 | messages: [],
311 | };
312 |
313 | componentWillMount() {
314 | subscribe(CHANNEL, messages => {
315 | this.setState({messages});
316 | });
317 | }
318 |
319 | renderItem({item}) {
320 | return (
321 |
322 | {item.sender}
323 | {item.message}
324 |
325 | );
326 | }
327 |
328 | render() {
329 | return (
330 |
331 |
332 |
333 | );
334 | }
335 | }
336 |
337 | const styles = StyleSheet.create({
338 | container: {
339 | flex: 1,
340 | backgroundColor: '#fff',
341 | },
342 | row: {
343 | padding: 20,
344 | borderBottomWidth: 1,
345 | borderBottomColor: '#eee',
346 | },
347 | message: {
348 | fontSize: 18,
349 | },
350 | sender: {
351 | fontWeight: 'bold',
352 | paddingRight: 10,
353 | },
354 | });
355 | ```
356 |
357 |
358 |
359 | ## Step 5. Typing up messages
360 |
361 | Next, we'll allow the user to send messages. We already have access to the `send` method of the chat server, we'll just need a text input where the user can type, and a "Send" button the user can press to send the typed message.
362 |
363 | Start by importing the [TextInput](https://facebook.github.io/react-native/docs/textinput.html) primitive from `react-native`:
364 | ```diff
365 | - import {StyleSheet, Text, View, FlatList} from 'react-native';
366 | + import {StyleSheet, Text, View, FlatList, TextInput} from 'react-native';
367 | ```
368 |
369 | Before we render the TextInput, we'll need a place to keep track of the text the user has typed. As you might remember from Step 2, we can use the component `state` for this. Let's amend the initial state on the top of the component declaration by adding a "typing" state variable that we'll update as the user types:
370 | ```diff
371 | state = {
372 | + typing: "",
373 | messages: [],
374 | };
375 | ```
376 |
377 | Now we can add our TextInput to our UI. Add the following lines into your `render` method, immediately after the `` component, but before the closing container `