React Native Blueprints
上QQ阅读APP看书,第一时间看更新

Adding state to our screen

As we have just seen, we will be using an attribute in our component's state named allProducts, which will contain the full list of products the user can add to the shopping list. 

We can initialize this state inside the component's constructor to give the user a gist of what he/she will be seeing on this screen even during the first run of the app (this is a trick used by many modern apps to onboard users by faking a used state):

/*** AddProduct.js ***/

...
constructor(props) {
super(props);
this.state = {
allProducts: [
{ id: 1, name: 'bread' },
{ id: 2, name: 'eggs' },
{ id: 3, name: 'paper towels' },
{ id: 4, name: 'milk' }
],
productsInList: []
};
}
...

Besides allProducts, we will also have a productsInList array, holding all the products which are already added to the current shopping list. This will allow us to mark the product as Already in shopping list, preventing the user from trying to add the same product twice in the list.

This constructor will be very useful for our app's first run but once the user has added products (and therefore saved them in persistent storage), we want those products to display instead of this test data. In order to achieve this functionality, we should read the saved products from AsyncStorage and set it as the initial allProducts value in our state. We will do this on componentWillMount:

/*** AddProduct.js ***/

...
async componentWillMount() {
const savedProducts = await AsyncStorage.getItem('@allProducts');
if(savedProducts) {
this.setState({
allProducts: JSON.parse(savedProducts)
});
}

this.setState({
productsInList: this.props.navigation.state.params.productsInList
});
}
...

We are updating the state once the screen is ready to be mounted. First, we will update the allProducts value by reading it from the persistent storage. Then, we will update the list productsInList based on what the ShoppingList screen has set as the state in the navigation property.

With this state, we can build our list of products, which can be added to the shopping list:

/*** AddProduct ***/

...
render(){
<List>
{this.state.allProducts.map(product => {
const productIsInList = this.state.productsInList.find(
p => p.id === product.id
);
return (
<ListItem key={product.id}>
<Body>
<Text
style={{
color: productIsInList ? '#bbb' : '#000'
}}
>
{product.name}
</Text>
{
productIsInList &&
<Text note>
{'Already in shopping list'}
</Text>
}
</Body>
</ListItem>
);
}
)}
</List>
}
...

Inside our render method, we will use an Array.map function to iterate and print each possible product, checking if the product is already added to the current shopping list to display a note, warning the user: Already in shopping list

Of course, we still need to add a better layout, buttons, and event handlers for all the possible user actions. Let's start improving our render method to put all the functionality in place.