# 商品管理介面-MerchandiseList

## 修改程式剛執行的初始畫面

在`src/navigator.js`新增一個MerchandiseList 畫面

```
import { StackNavigator } from 'react-navigation';

import Home from './containers/Home';
import Counter from './containers/Counter';
import Camera from './components/Camera';
import PersonalInfo from './components/PersonalInfo';
import MerchandiseList from './components/MerchandiseList';
import NewMerchandise from './components/NewMerchandise';

const AppNavigator = new StackNavigator(
  {
    Home: { screen: Home },
    Counter: { screen: Counter },
    Camera: { screen: Camera },
    PersonalInfo: { screen: PersonalInfo },
    MerchandiseList: { screen: MerchandiseList },
    NewMerchandise: { screen: NewMerchandise }
  },
  {
    headerMode: 'screen',
    navigationOptions: {
      header: null
    }
  }
);

export default AppNavigator;
```

`src/reducers/nav.js`的 `routes` 中的`routeName` 來決定初始畫面

```
import AppNavigator from '../navigator';

const initialState = {
  index: 0,
  routes: [{ key: 'Init', routeName: 'MerchandiseList', params: {} }]
};

export default (state = initialState, action) =>
  AppNavigator.router.getStateForAction(action, state);
```

## 使用Touchable 元件來增加回饋

使用`src/components/__data__/merchandise_list.json` 作為測試資料

`import MOCKDATA from './__data_/merchandise_list.json`

* 測試資料的資料結構

```
[
  {
    "picture_url": "https://cfshopeetw-a.akamaihd.net/file/08af7e4f7c83b53ee4d3acb2d1f19b88_tn",
    "discount": 0.8,
    "price": 200,
    "stars": 6819,
    "title":
      "[免運] 多件優惠 MIT台灣製-防潑水多功能桌上螢幕架 桌上架 鍵盤架 收納架 電腦架 ㄇ型架 ST004 居家大師",
    "count": 12
  },
  ...
]
```

* FlatList
  * data (資料來源)
  * renderItem (資料如何顯示)
  * keyExtractor (設置每個Item 的 Id)
* 使用`TouchableOpacity` 來實現Touch 的回饋與前往特定的頁面

```
  renderItem = ({ item }) => (
    <TouchableOpacity onPress={this.newMerchandise} activeOpacity={0.7}>
      <View style={styles.listItem}>
        <Image style={styles.thumbnail} source={ { uri: item.picture_url } } />
        <Text numberOfLines={1} ellipsizeMode="tail" style={styles.itemText}>
          {item.title}
        </Text>
      </View>
    </TouchableOpacity>
  );
```

* 在最下方增加新建商品的按鈕

```
 state = {
   data: MOCKDATA
 }
 render(){
   return (
     <View style={styles.container}>
        <FlatList
          style={styles.list}
          keyExtractor={this.keyExtractor}
          data={this.state.data}
          renderItem={this.renderItem}
        />

      <Button onPress={this.newMerchandise} title="新增商品" />
    </View>
   )
 }
```

* 圖文排版比例的設置 為 2:8

```
const styles = StyleSheet.create({
  itemText: {
    color: 'black',
    fontSize: 22,
    flex: 0.8
  },
  thumbnail: {
    width: 72,
    height: 72,
    flex: 0.2
  },

});
```

## 實現長按 item 的 ContextMenu，使用react-native 內建Modal 元件

* animationType 動畫類型，
  * `slide` 由下而上出現，而消失則由上而下的消失
  * ·`fade`淡入淡出的方式
* visible 是否顯示。
* `onRequestClose` 當Android 上的 back 鍵觸發。

```
   <Modal
      animationType="slide"
      transparent
      visible={this.state.visible}
      onRequestClose={() => {
        this.setState({
          visible: false
        });
      }}
    >
    {// Modal的內容，可以是個兩個按鈕的確認視窗 }
  </Modal>
```

* High Order Component 封裝了元件共用的行為，對行為做reuse ，而非對畫面做reuse
  * <https://reactjs.org/docs/higher-order-components.html>
* 實現connectModal hoc，並把openModal 與 closeModal 傳入，方便`WrappedComponent` 使用
* openModal 讓`WrappedComponent` 可以傳入自定義客製化的modalView
* openModal 也讓`WrappedComponent` 當下的context，譬如說當下的list item
* 此Modal 並非blocking Modal，所以也實現了讓使用者點任意地方可以關掉此Modal，參考`TouchableOpacity`的部分
* * 建立Modal 的 HOC
  * 加入Context
  * 使用方開始客製化他的畫面

```
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
  StyleSheet,
  View,
  ViewPropTypes,
  Text,
  Modal,
  TouchableWithoutFeedback,
  TouchableOpacity
} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  modalView: {
    flex: 1,
    backgroundColor: '#333a'
  },
  closeModalView: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0
  }
});

const EmptyComponent = () => {};
export default function connectModal(WrappedComponent) {
  return class AppModal extends Component {
    state = {
      visible: false,
      modalView: EmptyComponent
    };
    openModal = ({ modalView, context }) => {
      const ModalView = modalView || EmptyComponent;
      this.setState({
        modalView: () => <ModalView context={context} />,
        visible: true
      });
    };
    closeModal = () => {
      this.setState({
        visible: false
      });
    };
    render() {
      const WrappedContextModalView = this.state.modalView;
      return (
        <View style={styles.container}>
          <WrappedComponent
            {...this.props}
            openModal={this.openModal}
            closeModal={this.closeModal}
          />
          <Modal
            animationType="slide"
            transparent
            visible={this.state.visible}
            onRequestClose={() => {
              this.setState({
                visible: false
              });
            }}
          >
            <View style={styles.modalView}>
              <TouchableOpacity onPress={this.closeModal} style={styles.closeModalView} />
              <WrappedContextModalView context={this.state.context} />
            </View>
          </Modal>
        </View>
      );
    }
  };
}
```

在需要使用此Modal 的Modal 在export 之前，掛上connectModal ，並在item 按下後，開啟Modal ，並傳入自定義的畫面。

```
import connectModal from './hoc/connectModal';

class MerchandiseList {
  onMerchandisePress = (item) => {
    this.props.openModal({ modalView: this.modal, context: item });
  };
  modal = ({ context }) => (
    <View style={styles.modal}>
      <View style={styles.buttonContainer}>
        <Button
          color="red"
          title="刪除"
          onPress={() => {
            this.removeItem(context);
            this.props.closeModal();
          }}
        />
      </View>
    </View>
  );
  ...
}

export default connectModal(MerchandiseList);
```

在按鈕被按下後，呼叫closeModal 的動作


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zhang699-2.gitbook.io/react-native/shang-pin-guan-li-jie-mian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
