React Native - Menampilkan Data (Redux Storage) Part 1
Hello Sobat, Kali ini saya akan membahas mengenai cara membuat aplikasi React Native untuk menampilkan menggunakan ListView data dan menyimpan data menggunakan library Redux Storage, sebelum saya masuk ke langkah pembuatan aplikasi saya akan menjelaskan sedikit mengenai library redux storage, Redux Storage merupakan database lokal yang digunakan untuk melakukan penyimpanan dan library redux strorage juga bisa melakukan singkronisasi data, baik mungkin itu penjelasan singkat mengenai redux strorage jika ingin mengetahui lebih dalam mengenai libary ini kunjungi aja di sini, selanjutnya kita masuk ke langkah pembuatan aplikasinya.
Source Code
Create Aplikasi
Membuat aplikasi baru lihat vidio disini
Source Code
Create Aplikasi
Membuat aplikasi baru lihat vidio disini
Library
Menambahkan library masukan perintah pada terminal react-native <nama library> --save untuk lebih jelas lihat vidio disini, struktur library yang ditambahkan dalam bentuk json pada package.json
Class Aplikasi
Dibagian index.android.js tambahkan code berikut
Folderimport React, { Component } from 'react' import { Provider } from 'react-redux' import { createStore, applyMiddleware } from 'redux' import * as storage from 'redux-storage' import { Text, View, BackAndroid, AppRegistry } from 'react-native' import NavigationExperimental from 'react-native-deprecated-custom-components'; import AllSiswa from './app/components/view_allSiswa' import ApplicationStore from './app/reducers' const reducer = storage.reducer(ApplicationStore); import createEngine from 'redux-storage-engine-reactnativeasyncstorage' const engine = createEngine('notes-app-store') const middleware = storage.createMiddleware(engine) const createStoreWithMiddleware = applyMiddleware(middleware)(createStore) const store = createStoreWithMiddleware(reducer) const load = storage.createLoader(engine) load(store) const routes = [ { component: AllSiswa } ] class codeTRNote extends Component { componentDidMount() { } render() { return ( <Provider store={store}> <NavigationExperimental.Navigator style={{ flex: 1 }} ref='nav' initialRouteStack={routes} renderScene={this.renderScene} configureScene={this.configureScene} /> </Provider> ) } renderScene(route, navigator) { return <route.component navigator={navigator} {...route.passProps}/> } configureScene(route, routeStack) { if (route.type == 'addingSiswa') { return NavigationExperimental.Navigator.SceneConfigs.FloatFromBottomAndroid } if (route.type == 'editingSiswa'){ return NavigationExperimental.Navigator.SceneConfigs.FloatFromBottomAndroid } return NavigationExperimental.Navigator.SceneConfigs.FloatFromRight } } AppRegistry.registerComponent('codeTRNote', () => codeTRNote);
Struktur dari pembagian folder aplikasi, dari setiap folder harus dibuat secara manual mulai dari folder app di dalam folder app buat folder actions, components, lib, dan redurces
- file index.js pada folder actions
export const ADD_SISWA = 'ADD_SISWA' export const FETCH_SINGLE = 'FETCH_SINGLE' export const UPDATE_SISWA = 'UPDATE_SISWA' export const LOAD_STORED = 'LOAD_STORED' export const DELETE_SISWA = 'DELETE_SISWA' export function addSiswa(newSiswa) { return { type: ADD_SISWA, payload: newSiswa } } export function updateSiswa(updatedSiswa) { return { type: UPDATE_SISWA, payload: updatedSiswa } } export function deleteSiswa(siswaId) { return { type: DELETE_SISWA, payload: siswaId } }
- file style.js pada folder components
export const styles = { allSiswaContainer: { flex: 1, backgroundColor: '#ffffff' }, emptyListContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', marginBottom: 56 }, emptyList: { fontFamily: 'Lato-Bold', fontSize: 16 }, addNotesContainer: { flex: 1, backgroundColor: '#ffffff' }, textInputContainer: { flex: 1 }, inputSiswaStyle: { height: 60, paddingTop: 5, paddingLeft: 20, paddingRight: 20, paddingBottom: 0, fontFamily: 'Lato-Regular', fontSize: 20 }, }
- file view_allSiswa.js pada folder components
import React, { Component } from 'react' import { Text, View, StatusBar, TextInput, Alert, BackAndroid, ListView } from 'react-native' import { connect } from 'react-redux' import NewSiswa from './view_newSiswa' import SingleSiswa from './view_singleSiswa' import Toolbar from '../lib/Toolbar' import SiswaViewCard from '../lib/SiswaViewCard' import AddSiswaButton from '../lib/AddSiswaButton' import { deleteSiswa } from '../actions' import { styles } from './styles' import { getColor } from '../lib/helpers' import { Typo } from '../lib/Typography' import Icon from '../lib/Icon' class AllSiswa extends Component { constructor(props) { super(props) this._handleBackButton = this._handleBackButton.bind(this) } componentDidMount() { BackAndroid.addEventListener('hardwareBackPress', this._handleBackButton) } componentWillUnmount() { BackAndroid.removeEventListener('hardwareBackPress', this._handleBackButton) } _handleBackButton() { if (this.props.navigator.getCurrentRoutes().length == 1) { return false } return true } render() { return ( <View style={ styles.allSiswaContainer }> <StatusBar backgroundColor={getColor('paperBlue700')} barStyle="light-content" animated={true} /> <Toolbar title="Data Siswa" color={getColor('paperBlue')}/> { this.renderList() } <AddSiswaButton onBtnPress={this.addNewSiswa.bind(this)}/> </View> ) } addNewSiswa() { this.props.navigator.push({component: NewSiswa, type: 'addingSiswa'}) } goToSiswa(siswaId, nis, nama) { this.props.navigator.push({ component: SingleSiswa, type: 'editingSiswa', passProps: { siswaId, nis, nama } }) } longPressSiswa(siswaId) { Alert.alert( 'Hapus Siswa', 'Yakin ingin Hapus?', [ { text: 'Ya', onPress: () => this.deleteSiswa(siswaId) }, { text: 'Tidak' } ] ) } deleteSiswa(siswaId) { this.props.deleteSiswa(siswaId) } renderList() { if (this.props.siswa.length <= 0) { return ( <View style={styles.emptyListContainer}> <Icon name="delete" size={180} color={getColor('#f0f0f0')} /> <Text style={styles.emptyList}>Data Siswa Masih Kosong</Text> </View> ) } else { var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); var dataSource = ds.cloneWithRows(this.props.siswa) || [] return ( <ListView dataSource={dataSource} renderRow={(siswa, sectionID, rowID) => { return ( <SiswaViewCard nis={siswa.nis} nama={siswa.nama} id={siswa.id} keys={rowID} onPressBtn={this.goToSiswa.bind(this)} onLongPressBtn={this.longPressSiswa.bind(this)} /> ) }} /> ) } } } function mapStateToProps(state) { return { siswa: state.allSiswa } } export default connect(mapStateToProps, { deleteSiswa })(AllSiswa)
- file AddSiswaButton.js pada folder lib
import React, { Component } from 'react' import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' import { Typo } from './Typography' import { getColor } from './helpers' import Icon from './Icon' export default class AddSiswaButton extends Component { render() { return ( <View style={styles.container}> <TouchableOpacity onPress={this.handlePress.bind(this)}> <Icon name="add-circle" size={56} color={getColor('paperBlue')} /> </TouchableOpacity> </View> ) } handlePress() { this.props.onBtnPress() } } const styles = StyleSheet.create({ container: { position: 'absolute', bottom: 15, right: 15, backgroundColor: 'white', borderRadius: 50 } })
- file BackBtn.js pada folder lib
import React, { Component } from 'react' import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' import { Typo } from './Typography' import { getColor } from './helpers' import Icon from './Icon' export default class BackBtn extends Component { render() { return ( <View style={styles.container}> <TouchableOpacity onPress={this.handlePress.bind(this)}> <Icon name="close" size={36} color={getColor('#ffffff')} /> </TouchableOpacity> </View> ) } handlePress() { this.props.onBtnPress() } } const styles = StyleSheet.create({ container: { position: 'absolute', padding: 5, bottom: 15, left: 15, backgroundColor: getColor('paperPink'), borderRadius: 50 } })
- file config.js pada folder lib
import { typography, color } from './paper_styles' export const COLOR = color export const TYPO = typography export const PRIMARY = 'paperBlue' export const COLOR_NAME = [ 'googleBlue', 'googleGreen', 'googleGrey', 'googleRed', 'googleYellow', 'paperAmber', 'paperBlue', 'paperBlueGrey', 'paperBrown', 'paperCyan', 'paperDeepOrange', 'paperDeepPurple', 'paperGreen', 'paperGrey', 'paperIndigo', 'paperLightBlue', 'paperLightGreen', 'paperLime', 'paperOrange', 'paperPink', 'paperPurple', 'paperRed', 'paperTeal', 'paperYellow' ] export const THEME_NAME = ['light', 'dark'];
- file helpers.js pada folder lib
import { PRIMARY, COLOR } from './config' // Detect whether a color is a hex code/rgba or a paper element style export function getColor(string) { if (string) { if (string.indexOf('#') > -1 || string.indexOf('rgba') > -1 || string.indexOf('rgb') > -1) { return string } if (COLOR[string]) { return COLOR[string].color } if (COLOR[`${string}500`]) { return COLOR[`${string}500`].color } } return COLOR[`${PRIMARY}500`].color }
- file icon.js pada folder lib
import React, { Component, PropTypes } from 'react' import { View } from 'react-native' import { default as VectorIcon } from 'react-native-vector-icons/MaterialIcons' import { getColor } from './helpers' // example -> // <Icon name="google" size={24} color={COLOR[`${primary}500`].color} /> export default class Icon extends Component { static propTypes = { name: PropTypes.string.isRequired, style: View.propTypes.style, size: PropTypes.number, color: PropTypes.string, allowFontScaling: PropTypes.bool } static defaultProps = { size: 30, color: '#757575', allowFontScaling: true } render() { const { name, style, size, color, allowFontScaling } = this.props return ( <VectorIcon name={name} size={size} color={getColor(color)} style={style} allowFontScaling={allowFontScaling} /> ) } }
- file paper_style.js pada folder lib download disini
- file SiswaViewCard.js pada folder lib
import React, { Component } from 'react' import { View, Text, TouchableOpacity, StyleSheet } from 'react-native' import { Typo } from './Typography' import { getColor } from './helpers' export default class SiswaViewCard extends Component { render() { const { nis, nama, id, keys } = this.props const background = (keys % 2 == 0) ? { backgroundColor: '#ffffff' } : { backgroundColor: '#f2f2f2'} return ( <TouchableOpacity onPress={this.handleGoto.bind(this)} onLongPress={this.handleLongPress.bind(this)}> <View style={[ styles.cardContainer, background ]}> <View style={styles.cardTitleContainer}> <Text style={[ styles.cardTitle, Typo.cardTitle ]}> {nis.toUpperCase()} </Text> </View> <View style={styles.cardDescriptionContainer}> <Text style={[ styles.cardDescription, Typo.cardDescription ]}> {(nama.length > 30) ? nama.slice(0, 30) + '...' : nama} </Text> </View> </View> </TouchableOpacity> ) } handleLongPress() { this.props.onLongPressBtn(this.props.id) } handleGoto() { this.props.onPressBtn(this.props.id, this.props.nis, this.props.nama) } } const styles = StyleSheet.create({ cardContainer: { paddingLeft: 10, paddingRight: 10, paddingTop: 15, paddingBottom: 15 }, cardTitleContainer: { justifyContent: 'center' }, cardTitle: { marginBottom: 10 }, cardDescriptionContainer: { }, cardDescription: { } })
- file TickBtn.js pada folder lib
import React, { Component } from 'react' import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' import { Typo } from './Typography' import { getColor } from './helpers' import Icon from './Icon' export default class TickBtn extends Component { render() { return ( <View style={styles.container}> <TouchableOpacity onPress={this.handlePress.bind(this)}> <Icon name="save" size={36} color={getColor('#ffffff')} /> </TouchableOpacity> </View> ) } handlePress() { this.props.onBtnPress() } } const styles = StyleSheet.create({ container: { position: 'absolute', padding: 5, bottom: 15, right: 15, backgroundColor: getColor('paperBlue'), borderRadius: 50 } })
- file Toolbar.js pada folder lib
import React, { Component } from 'react' import { View, Text, StyleSheet } from 'react-native' import { Typo } from './Typography' import { getColor } from './helpers' export default class Toolbar extends Component { render() { const { color, title } = this.props return ( <View style={[ styles.toolbar, { backgroundColor: getColor(color) } ]}> <Text style={[ styles.title, Typo.toolbarTitle ]}> {title.toUpperCase()} </Text> </View> ) } } const styles = StyleSheet.create({ toolbar: { height: 56, justifyContent: 'center' }, title: { marginLeft: 16, color: 'white' } })
- file Typography.js pada folder lib
export const Typo = { toolbarTitle: { fontFamily: 'Lato-Bold', fontSize: 18 }, cardTitle: { fontFamily: 'Lato-Bold', fontSize: 16 }, cardDescription: { fontFamily: 'Lato-Regular', fontSize: 14, lineHeight: 20 } }
- file index.js pada folder reducers
import { combineReducers } from 'redux' import SiswaReducer from './reducer_siswa' import CurrentSiswaReducer from './reducer_current' const rootReducer = combineReducers({ allSiswa: SiswaReducer, currentSiswa: CurrentSiswaReducer }) export default rootReducer
- file reduces_current.js pada folder reducers
import { FETCH_SINGLE } from '../actions' export default (state = {}, action) => { switch(action) { case FETCH_SINGLE: return action.payload default: return state } }
- file reduces_siswa.js pada folder reducers
import _ from 'lodash' import { ADD_SISWA, UPDATE_SISWA, DELETE_SISWA } from '../actions' const initialState = [ ] export default (state = initialState, action) => { switch(action.type) { case ADD_SISWA: const newSiswa = Object.assign({}, { id: state.length }, action.payload) const newState = [newSiswa, ...state] return newState case UPDATE_SISWA: const newArray = _.remove(state, (data) => { return data.id != action.payload.id }) const updatedSiswa = Object.assign({}, { id: newArray.length }, action.payload) const updatedState = [updatedSiswa, ...newArray] return updatedState case DELETE_SISWA: console.log('get request') console.log(action.payload) const deletedNewArray = _.remove(state, (data) => { return data.id != action.payload }) return deletedNewArray default: return state } }
Untuk penempatan aplikasi lebih jelasnya lihat vidio
Output Aplikasi
Sekian artikel dari saya semoga bermanfaat, jika ada yang ditanyakan comment saja di bawah.
Sumber github (editing source code)
boleh lihat source code di github?
ReplyDelete