Now here is an interesting problem; we have come across this great framework for making fast differences between the Virtual DOM and its native components. How do we tell React Native what UI to represent or when to change it? A React Native component is a simple, reusable, function-like object that enables us to describe the native mobile components we want to render. They will always contain properties, state, and a render method. Let's start really simple by creating our own component.
Creating a new component in React Native will look similar to the following:
import React, { Text, View } from 'react-native'; class HelloComponent extends React.Component { render () { return ( <View> <Text>Hello React</Text> <View> ); } }
Wait a second… What are these weird XML elements doing in my JavaScript code? Facebook has created its own syntactic extension over JavaScript to describe React components. Here is the exact same code, but written in ordinary JavaScript:
var HelloComponent = React.createClass({displayName: "HelloComponent"}, render: function () { return ( React.createElement(View, null, React.createElement(Text, null, "Hello React") ) ));
While it is possible to write React Native applications only in JavaScript, the previous syntax includes many added benefits for the developer.
JavaScript XML (JSX) is an XML-like extension to the ECMAScript specification. It combines the component logic (JavaScript) and markup (DOM or Native UI) into a single file.
A JSX Element will take the following form:
var element = ( <JSXElement> <SubJSXElement /> <SubJSXElement /> <SubJSXElement /> <JSXElement /> );
The JSX specification also defines the following:
<JSXElement></JSXElement>
or self-closing <JSXElement />
.{}
or string ""
<Component attr="attribute">
. Expressions are JavaScript snippets.This is cool! We have gone from a deeply nested and imperative JavaScript code to a declarative format that describes the exact elements that we want to see in our components. There is no separation of concerns since our logic is coupled with our markup, making the components easier to debug and test. Since you can always include the same component in multiple other components, there is no need to duplicate the code anyway.
Note that JSX is only meant to be used as a preprocessor and it is not recommended to transpile in your production build. More information on JSX can be found in the official React documentation https://facebook.github.io/react/docs/jsx-in-depth.html or in the official JSX Specification https://facebook.github.io/jsx/.
There are a few things that we have overlooked in our component. View and Text are two of the many components provided by React Native to build a UI. These are not regular components that render in the JavaScript layer, they can map directly to their native container parts! The View component maps to UIView
in IOS and android.view
in Android, while Text is the generic component to display text on each platform respectively. View and Text support various functions, such as layouts, styling, and touch handling.
Displaying the same static text over and over is not very exciting. Let's extend this simple component and add some more functionalities.
At this point, you may be wondering how React Native deals with component manipulation and communication as the number of components grows into a component hierarchy. A component hierarchy, similar to a tree, starts with a root component and can contain many children. React Native provides two methods of data passing; one for data-flow down the component hierarchy and another for maintaining internal state.
How do the components in the same component hierarchy communicate with each other? Data is passed down through properties commonly known as props. Props are considered to be immutable by convention and should never be modified directly. To pass a prop into a component, just add a camel-cased attribute to the component:
<HelloComponent text="Hello React" />
Props can be accessed internally in the component through this.props
:
import React, { Text, View } from 'react-native'; class HelloComponent extends React.Component { render () { return ( <View> <Text>{this.props.text}</Text> View> ); } }
It is not always necessary to include props with a component, but if you require a default value for your props, you can assign the defaultProps
object to the component's class constructor.
HelloComponent.defaultProps = {text: "Default Text!"};
If you are planning to expose your component to the public, it makes sense to constrain the ways developers can use it. To enforce that your components are being used correctly, the
PropTypes module can be used to validate any props passed in. In the event that a prop does not pass the propType
validation, a warning is shown to the developer in the console. The PropTypes
cover a wide range of JavaScript types and primitives, including nested objects. You can define propTypes
on a component's class constructor:
HelloComponent.propTypes = {text: React.PropTypes.string};
For more information on propTypes
, visit the Prop Validation section of React Docs https://facebook.github.io/react/docs/reusable-components.html.
So now we can pass in the data, but what if the data changes, then how can we display these changes to the user? Components can optionally contain state, a mutable and private set of data. State is a great way to keep track of user input, asynchronous requests, and events. Let's update our component with additional text when the user interacts with it:
import React, { Text, View, Component } from 'react-native'; class HelloComponent extends React.Component{ constructor (props) { super(props); this.state = { // Set Initial State appendText: '' }; } render () { return ( <View> <Text onPress={() => setState({text: ' Native!'})}>{this.props.text + this.state.appendText}</Text> <View> ); } }
Touching the
Text
component will trigger the function in its onPress
prop. We are taking advantage of the ES6 arrow syntax to include our functionality in line with the text component.
The setState
function will merge the object you pass into the first argument with the current state of the component. Calling setState
will trigger a new render where, instead of being empty, this.state.appendText
will append Native! to the value of text, which we originally passed in from props. The final result is "Hello React" + " Native!"
to produce "Hello React Native!"
.
Never try and modify the value of this state on your own. Directly changing the state could result in data loss during the next setState
call and it will not trigger another re-render.
3.147.46.58