Handling state

React applications have state that gets passed down to components that render features and require state data. For example, imagine that you're designing an app that uses react-navigation and different screens depend on the same state data. How do you get state data into these screen components? How do they update the application state?

To start with, let's think about where to put your application state. The most natural place to put it would be the App component. So far in this chapter, the examples have directly exported calls to createStackNavigator(). This function is a higher-order function - it returns a new React component. This means that you can wrap your own stateful component around the navigation component that's returned by createStackNavigator().

To illustrate this idea, let's revisit the example from earlier where you have a Home screen that lists item buttons that navigate to a Details screen. Here's what the new App component looks like:

import React, { Component } from 'react';
import { createStackNavigator } from 'react-navigation';
import Home from './Home';
import Details from './Details';

const Nav = createStackNavigator(
{
Home,
Details
},
{ initialRouteName: 'Home' }
);

export default class App extends Component {
state = {
stock: {
first: 1,
second: 0,
third: 200
}
};

updateStock = id => {
this.setState(({ stock }) => ({
stock: {
...stock,
[id]: stock[id] === 0 ? 0 : stock[id] - 1
}
}));
};

render() {
const props = {
...this.state,
updateStock: this.updateStock
};

return <Nav screenProps={props} />;
}
}

First, you use the createStackNavigator() function to create your navigator component:

const Nav = createStackNavigator(
{
Home,
Details
},
{ initialRouteName: 'Home' }
);

Now you have a Nav component that you can render. Next, you can create a regular React component with state:

export default class App extends Component {
state = {
stock: {
first: 1,
second: 0,
third: 200
}
};
...
}

The state used in this component represents the number quantity of each item that is available to buy. Next, you have the updateStock() function that is used to update the stock state for a given item ID:

updateStock = id => {
this.setState(({ stock }) => ({
stock: {
...stock,
[id]: stock[id] === 0 ? 0 : stock[id] - 1
}
}));
};

The ID that's passed to this function has its stock state decremented by 1, unless it's already at 0. This function can be used when the Buy button is clicked for the item to check its stuck quantity by 1. Finally, you have the render() method, which can render the Nav component:

render() {
const props = {
...this.state,
updateStock: this.updateStock
};

return <Nav screenProps={props} />;
}

The state of App is passed to Nav as props. The updateStock() function is also passed as a prop so that it can be used by the screen components. Now let's take a look at the Home screen:

import React from 'react';
import { View, Button } from 'react-native';

import styles from './styles';

const Home = ({ navigation, screenProps: { stock } }) => (
<View style={styles.container}>
<Button
title={`First Item (${stock.first})`}
onPress={() =>
navigation.navigate('Details', {
id: 'first',
title: 'First Item',
content: 'First Item Content'
})
}
/>
<Button
title={`Second Item (${stock.second})`}
onPress={() =>
navigation.navigate('Details', {
id: 'second',
title: 'Second Item',
content: 'Second Item Content'
})
}
/>
<Button
title={`Third Item (${stock.third})`}
onPress={() =>
navigation.navigate('Details', {
id: 'third',
title: 'Third Item',
content: 'Third Item Content'
})
}
/>
</View>
);

Home.navigationOptions = {
title: 'Home'
};

export default Home;

Once again, you have the three Button components that navigate to the Details screen and pass route parameters. There's a new parameter added in this version: id. The title of each button reflects the stock count of the given item. This value is part of the application state and is passed to the screen component via properties. However, these properties are all accessed through the screenProps property.

Rule of thumb: If a prop is passed to the navigation component, it's accessible via the screenProps property. If a value is passed to the screen via navigator.navigate(), it's accessible by calling navigator.getParam().

Let's take a look at the Details component next:

import React from 'react';
import { View, Text, Button } from 'react-native';

import styles from './styles';

const Details = ({ navigation }) => (
<View style={styles.container}>
<Text>{navigation.getParam('content')}</Text>
</View>
);

Details.navigationOptions = ({
navigation,
screenProps: { stock, updateStock }
}) => {
const id = navigation.getParam('id');
const title = navigation.getParam('title');

return {
title,
headerRight: (
<Button
title="Buy"
onPress={() => updateStock(id)}
disabled={stock[id] === 0}
/>
)
};
};

export default Details;

The id and the title route parameters are used to manipulate content in the navigation bar. The title parameter sets the title. The id is used by the onPress handler of the Buy button, by passing it to updateStock(), and the appropriate item stock count is updated when the button is pressed. The disabled property also relies on the id parameter to look up the stock quantity. Just like the Home screen, the stock and updateStock() props that are passed down from the App component are accessible through the screenProps app.

Here's what the Home screen looks like when it's first rendered:

The stock quantity is reflected in each item button as a number. Let's press the First Item button and navigate to the Details page:

The Buy button in the navigation bar is enabled because the stock quantity is 1. Let's go ahead and press the Buy button and see what happens:

After pressing the Buy button, it becomes disabled. This is because the stock value for this item was 1. By pressing Buy, you caused the updateStock() function to be called, which updated this value to 0. As a result of the state change, the App component re-rendered the Nav component, which, in turn re-rendered your Details screen component with new prop values.

Let's go back to the Home screen and see what's changed there as a result of the state update:

As expected, the stock quantity that is rendered beside the First Item button text is 0, reflective of the state change that just happened.

This example shows that you can have a top-level App component handle the application state while passing it down to the individual app screens, along with the functions that issue state updates.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.64.132