官术网_书友最值得收藏!

Adding event handlers 

All the interaction with the user will happen through event handlers in React Native. Depending on the controller, we will have different events which can be triggered. The most common event is onPress, as it will be triggered every time we push a button, a checkbox, or a view in general. Let's add some onPress handlers for all the components which can be pushed in our screen:

/*** ShoppingList.js ***/

...
render() {
return (
<Container>
<Content>
<List>
{this.state.products.map(p => {
return (
<ListItem
key={p.id}
onPress={this._handleProductPress.bind(this, p)}
>
<Body>
<Text style={{ color: p.gotten ? '#bbb' : '#000' }}>
{p.name}
</Text>
</Body>
<Right>
<CheckBox
checked={p.gotten}
onPress={this._handleProductPress.bind(this, p)}
/>
</Right>
</ListItem>
);
})}
</List>
</Content>
<Fab
style={{ backgroundColor: '#5067FF' }}
position="bottomRight"
onPress={this._handleAddProductPress.bind(this)}
>
<Icon name="add" />
</Fab>
<Fab
style={{ backgroundColor: 'red' }}
position="bottomLeft"
onPress={this._handleClearPress.bind(this)}
>
<Icon ios="ios-remove" android="md-remove" />
</Fab>
</Container>
);
}
...

Notice we added three onPress event handlers:

  • On <ListItem>, to react when the user taps on one product in the list
  • On <CheckBox>, to react when the user taps on the checkbox icon next to every product in the list
  • On both the <Fab> buttons

If you know React, you probably understand why we use .bind in all our handler functions, but, in case you have doubts, .bind will make sure we can use this inside the definition of our handlers as a reference to the component itself instead of the global scope. This will allow us to call methods inside our components as this.setState or read our component's attributes, such as this.props and this.state.

For the cases when the user taps on a specific product, we also bind the product itself, so we can use them inside our event handlers.

Now, let's define the functions which will serve as event handlers:

/*** ShoppingList.js ***/

...
_handleProductPress(product) {
this.state.products.forEach(p => {
if (product.id === p.id) {
p.gotten = !p.gotten;
}
return p;
});

this.setState({ products: this.state.products });
}
...

First, let's create a handler for when the user taps on a product from our shopping list or in its checkbox. We want to mark the product as gotten (or unmark it if it was already gotten), so we will update the state with the product marked properly.

Next, we will add a handler for the blue <Fab> button to navigate to the AddProduct screen:

/*** ShoppingList.js ***/

...
_handleAddProductPress() {
this.props.navigation.navigate('AddProduct', {
addProduct: product => {
this.setState({
products: this.state.products.concat(product)
});
},
deleteProduct: product => {
this.setState({
products: this.state.products.filter(p => p.id !== product.id)
});
},
productsInList: this.state.products
});
}
...

This handler uses this.props.navigation, which is a property automatically passed by the Navigator component from react-navigation. This property contains a method named navigate, receiving the name of the screen to which the app should navigate plus an object which can be used as a global state. In the case of this app, we will store three keys:

  • addProduct: One function to allow the AddProduct screen to modify the ShoppingList component's state to reflect the action of adding a new product to the shopping list.
  • deleteProduct: One function to allow the AddProduct screen to modify the ShoppingList component's state to reflect the action of removing a product from the shopping list.
  • productsInList: A variable holding the list of products is already on the shopping list, so the AddProducts screen can know which products were already added to the shopping list and display those as "already added", preventing the addition of duplicate items.

Handling state within the navigation should be seen as a workaround for simple apps containing a limited number of screens. In larger apps (as we will see in later chapters), a state management library, such as Redux or MobX, should be used to keep the separation between pure data and user interface handling.

We will add the last handler for the blue <Fab> button, which enables the user to clear all the items in the shopping list in case you want to start a new list:

/*** ShoppingList.js ***/

...
_handleClearPress() {
Alert.alert('Clear all items?', null, [
{ text: 'Cancel' },
{ text: 'Ok', onPress: () => this.setState({ products: [] }) }
]);
}
...

We are using Alert to prompt the user for confirmation before clearing all the elements in our shopping list. Once the user confirms this action, we will empty the products attribute in our component's state.

主站蜘蛛池模板: 虎林市| 新源县| 大竹县| 漠河县| 甘孜县| 上饶县| 格尔木市| 惠水县| 昌图县| 海兴县| 高要市| 靖远县| 永安市| 元阳县| 安国市| 新建县| 连州市| 五原县| 新干县| 遂川县| 廉江市| 临颍县| 改则县| 沽源县| 无为县| 郸城县| 河南省| 栖霞市| 中方县| 灵宝市| 新巴尔虎右旗| 金塔县| 左云县| 柯坪县| 尼玛县| 盐津县| 安溪县| 定州市| 隆回县| 牡丹江市| 武清区|