ReactNative: Component encapsulation (e.g. secondary menu components)

Posted by farkewie on Fri, 12 Jun 2020 04:17:07 +0200

1. Introduction

Previously, the basic API and UI components of RN are introduced. These components exist in the form of granularity in complex composite components. How to effectively and reasonably use them for packaging is very necessary.There are many benefits to developing composite components, most notably reuse and independent functional modules.Composite components are divided into two types, one is static, this component does not have the characteristics of reuse, composed of static data, can be developed static pages, regardless of data transfer.The other is dynamic component, which can achieve the effect of component reuse by receiving external dynamic data.

 

2. Application

Dynamic components have many applications, the most typical of which are secondary menu components, fixed style, variable data, and refreshing secondary directory data interactively through the selection of primary directory.The idea is simple: first, build a data model; second, break down the components to be encapsulated at this granularity, then build the components at this granularity; then, set up the component's property interface; then, design the component rendering rules and decompose the rendering, bind events; and finally, reference the encapsulated components and pass them into the data model.A complete example is as follows:

HeadList.js[Granularity component: header tag]

import React, { Component } from 'react';
import {
    StyleSheet,
    View,
    Text,
    TouchableOpacity
} from 'react-native';

export default class HeadList extends Component{

    render(){

        let headData = this.props.data;
        let update = this.props.update;
        const count = headData.length;

        return (
            <View style={style.flex}>
                {
                    headData.map( function(item,i){
                        return (
                            <View style={[style.center,{flex:1/count}]} key={i}>
                                <TouchableOpacity onPress={ () => {update(headData[i])}}>
                                    <Text style={style.head_text}>
                                        {item}
                                    </Text>
                                </TouchableOpacity>
                            </View>
                        )
                    })
                }
            </View>
        )
    }
}

const style = StyleSheet.create({
    flex: {
        flex: 1,
        flexDirection: 'row'
    },
    head_text: {
        color: '#7B7B7B',
        fontSize: 20
    },
    center: {
        justifyContent: "center",
        alignItems: "center"
    }
});

LeftList.js[Granularity Component: Level 1 Catalog]

import React, { Component } from 'react';
import {
    StyleSheet,
    View,
    ScrollView,
    TouchableOpacity,
    Text,
    Dimensions
} from 'react-native';

const {width} = Dimensions.get('window');

export default class LeftList extends Component{

    constructor(props){
        super(props);
        this.state = {
            selectIndex:0
        };
    }

    updateState(index,update,leftData){

        //Trigger Callback Function
        update(leftData[index]);

        //Rendering cell colour
        this.setState({
            selectIndex:index
        })
    };

    componentWillReceiveProps(nextProps): void {
        if (nextProps.shouldChangeTab) {
            //Rendering cell colour
            this.setState({
                selectIndex:0
            })
        }
    }

    render(){

        let leftData = this.props.data;
        let update = this.props.update;
        let {selectIndex} = this.state;

        return (
            <ScrollView style={style.container}>
                {
                    leftData.map( (item,i) => {
                        return (
                            <View key={i} style={[style.list_cell,style.center, selectIndex === i ?
                                style.selectBgColor : style.normalBgColor]}>

                                <TouchableOpacity onPress = { this.updateState.bind(this,i,update,leftData) } >

                                    <Text style={[style.list_text,style.list_margin]}>
                                        {item}
                                    </Text>

                                </TouchableOpacity>

                            </View>
                        )
                    })
                }
            </ScrollView>
        )
    }
}

const style = StyleSheet.create({
    container: {
        flex:1,
        width: width/2,
        backgroundColor:'#F2F2F2'
    },
    list_text: {
        color: '#7B7B7B',
        fontSize: 18
    },
    list_margin: {
        marginLeft: 20
    },
    list_cell: {
        height: 60
    },
    center: {
        justifyContent: "center"
    },
    selectBgColor: {
        backgroundColor:'#FFFFFF'
    },
    normalBgColor: {
        backgroundColor:'#F2F2F2'
    }
});

RightList.js[Granularity component: secondary directory]

import React, { Component } from 'react';
import {
    ScrollView,
    StyleSheet,
    Text,
    TouchableOpacity,
    View,
    Dimensions
} from 'react-native';

const {width} = Dimensions.get('window');

export default class RightList extends Component{

    render(){

        let rightData = this.props.data;

        return (
            <ScrollView style={style.container}>
                {
                    rightData.map( function(item,i){
                        return (
                            <View key={i} style={[style.list_cell,style.center]}>
                                <TouchableOpacity>
                                    <Text style={[style.list_text,style.list_margin]}>
                                        {item}
                                    </Text>
                                </TouchableOpacity>
                            </View>
                        )
                    })
                }
            </ScrollView>
        )
    }
}

const style = StyleSheet.create({
    container: {
        flex:1,
        width: width/2,
        backgroundColor:'#FFFFFF'
    },
    list_text: {
        color: '#7B7B7B',
        fontSize: 18
    },
    list_margin: {
        marginLeft: 20
    },
    list_cell: {
        height: 60
    },
    center: {
        justifyContent: "center"
    }
});

MenuList.js[Encapsulated Component]

import React, { Component } from 'react';
import {
    StyleSheet,
    View,
    Dimensions
} from 'react-native';

import HeadList from './HeadList'
import LeftList from "./LeftList";
import RightList from "./RightList";

const {height} = Dimensions.get('window');

let data = {};
let headData = [];
let leftData = [];
let rightData = [];

export default class MenuList extends Component{

    constructor(props){
        super(props);
        data = props.data;

        //Initialize header data
        for (let item in data){
            headData.push(item);
        }

        //Initialize left data
        let defaultLValue = headData[0];
        for (let item in data[defaultLValue]){
            leftData.push(item);
        }

        //Initialize right data
        let defaultRValue = leftData[0];
        rightData = data[defaultLValue][defaultRValue];

        //Initialization state
        this.state = {
            shouldChangeTab: false,
            currentTab: defaultLValue,
            leftData : leftData,
            rightData : rightData
        };
    }

    //Function callback, choosing the header each time tab After that, restart render
    forceUpdateAllUI = (ele) => {
        leftData = [];
        for (let item in data[ele]){
            leftData.push(item);
        }
        let defaultRValue = leftData[0];
        rightData = data[ele][defaultRValue];

        this.setState({
            shouldChangeTab:true,
            currentTab: ele,
            leftData: leftData,
            rightData: rightData
        })
    };

    //Function callback, after each selection of the list on the left, restart render
    forceUpdateRightListUI = (ele) => {
        rightData = data[this.state.currentTab][ele];
        this.setState({
            shouldChangeTab:false,
            rightData: rightData
        })
    };

    render(){
        return (
            <View style={style.container}>
                <View style={style.top}>
                    <HeadList data={headData} update={this.forceUpdateAllUI}/>
                </View>
                <View style={style.bottom}>
                    <LeftList data={this.state.leftData}
                              shouldChangeTab={this.state.shouldChangeTab}
                              update={this.forceUpdateRightListUI}
                    />
                    <RightList data={this.state.rightData}/>
                </View>
            </View>
        )
    }
}

const style = StyleSheet.create({
    container: {
        flex: 1,
        height: height,
        borderTopWidth: 1,
        borderBottomWidth: 1,
        borderColor: '#ddd'
    },
    top: {
        height: 60,
        borderBottomWidth: 1,
        borderColor:'#DFDFDF',
        backgroundColor:'#F5F5F5'
    },
    bottom: {
        height: height-60,
        flexDirection:'row',
        backgroundColor: '#F5FCFF'
    }
});

Index.ios.js[Referencing composite components]

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    View,
    StatusBar
} from 'react-native';
import MenuList from "./src/MenuList";

const data1 = {
    "All areas": {
        "All areas": ["All areas"],
        "Top Business Circles": [
            "hongqiao district",
            "Xujiahui Area",
            "Huaihai Road Business District",
            "Jing'an Temple Area",
            "Shanghai Railway Station Area",
            "Pudong Lujiazui Financial and Trade Zone",
            "North Sichuan Road Business District",
            "People's Square Area",
            "Nanxiang, Anting Auto City"
        ],
        "Popular Administrative Areas": [
            "Jing'an District",
            "Xuhui District",
            "Changning District",
            "Huangpu District",
            "Iris Region",
            "Baoshan District",
            "zhabei district"
        ]
    },
    "Metro Line":{
        "Metro Line":["Metro Line"],
        "Line 1":["Jun Station","Waihuanlu","Lianhua Road Station","Jinjiang Park Station","shanghai south railway station","Caobao Road"],
        "Line 2":["Pudong International Airport Station","Haitiansan Road Station","Yuandong Avenue Station","Lingkong Road Station"]
    }
};

const data2 = {
    "Language":{
        "All":["All"],
        "Web Front End":["HTML","CSS","JavaScript"],
        "Server":["Node.js","Java","Python","Ruby","Php"]
    },
    "Tool":{
        "All":["All"],
        "Apple":["Xcode"],
        "Other":["Sublime Text","WebStorm","Visual Studio Code"]
    }
};

StatusBar.setHidden(true);

export default class RNComponentPackage extends Component {

    render() {
        return (
            <View style={styles.container}>
                <MenuList data={data1}/>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#FFFFFF',
    }
});

AppRegistry.registerComponent('RNComponentPackage', () => RNComponentPackage);

  

3. Demonstration

 

Topics: React iOS github Javascript