This is a react native app. Make sure you have expo installed.
make sure to type ‘npm install’ to install all the packages.
Then type ‘npm start’.
Blogs
We install redux, and then import it for usage.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import React from 'react'; import { StyleSheet, Text, View, Button, ScrollView, TouchableOpacity } from 'react-native'; import { createStore, bindActionCreators } from 'redux'; console.log('Blogs.js - create reducer function'); const reducer = (state = {comments:[], blogs:[]}, action) => { switch(action.type) { case 'COMMENTS': return { ...state, comments: action.payload.commentArray } case 'BLOGS': return { ...state, blogs: action.payload.blogArray } default: return state; } }; console.log('Blogs.js - create the store with a reducer function √ '); export const store = createStore(reducer); export default class Blogs extends React.Component { componentDidMount() { console.log(' -- componentDidMount -- ' ); var self = this; var blogsPromise = new Promise(function(resolve, reject) { console.log(' -- load blogs FromServer -- ' ); fetch("https://jsonplaceholder.typicode.com/posts", { method: 'get' }) .then(response => response.json()) .then(blogs => { store.dispatch({ type: 'BLOGS', payload: {blogArray:blogs} }); resolve(true); }) .catch(function(err) {}); }); var self = this; var commentsPromise = new Promise(function(resolve, reject){ console.log(' -- load comments FromServer -- ' ); fetch("https://jsonplaceholder.typicode.com/posts/1/comments", { method: 'get' }) .then(response => response.json()) .then(comments => { store.dispatch({ type: 'COMMENTS', payload: {commentArray:comments} }); resolve(true); }) .catch(function(err) {}); }); Promise.all([blogsPromise, commentsPromise]).then(function(values) { console.log(' -- Promise all completed -- '); self.props.screenProps.assignComments(store.getState().a); }); // when store changes, do something here store.subscribe(() => { console.log('Blogs.js - subscribe to updates'); var state = store.getState(); }); } constructor() { console.log('√ Blogs.js - constructor'); super(); this.handleNavigate = this.handleNavigate.bind(this); } handleNavigate(blogId) { var self = this; this.props.screenProps.assignNewBlogId(blogId, function() { self.props.navigation.navigate('CommentsScreen'); }); } render() { return ( <View> <ScrollView> { store.getState().blogs.map((item,index)=>( <View key = {item.id} styles = {styles.row}> <TouchableOpacity style = {styles.title} onPress={() => this.handleNavigate(item.id)} > <Text>{item.title}</Text> </TouchableOpacity> <Text style = {styles.item} >{item.body}</Text> </View> )) } </ScrollView> </View> ); } } const styles = StyleSheet.create ({ item: { flexDirection: 'column', justifyContent: 'space-evenly', alignItems: 'flex-start', borderColor: '#f4f4f4', borderWidth: 1, backgroundColor: 'white', fontSize: 12, textAlign: "left", padding: 8, marginBottom: 20, }, title: { backgroundColor: '#FE434C', alignItems: 'center', justifyContent: 'center', borderRadius: 10, margin: 10, height: 40, }, }) |
Comments
We import the store variable from Blogs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
import React from 'react'; import { StyleSheet, Text, View, Button, ScrollView } from 'react-native'; import { store } from './Blogs'; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, commentRow: { backgroundColor: '#f0f0f0', padding: 0, borderRadius: 4, borderWidth: 0.5, borderColor: '#d6d7da', padding: 10, }, commentName: { padding: 5, backgroundColor: '#ff0000', }, commentBody: { backgroundColor: '#00ff00', }, }); export default class Comments extends React.Component { render() { return ( <ScrollView> <Text>Comments for blog id {this.props.screenProps.currentBlogId}</Text> { store.getState().comments.filter((item) => { return item.postId == this.props.screenProps.currentBlogId; }).map((item, index) => ( <View style={styles.commentRow} key={item.id}> <Text style={styles.commentName}>{item.name}, {item.email}</Text> <Text style={styles.commentBody}>{item.body}</Text> </View> )) } </ScrollView> ) } } |
AppContainer
Let’s configure our react navigation.
We also implemented our Blogs and Comments components above. We would use these components.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import { createStackNavigator, createAppContainer } from 'react-navigation'; import Blogs from './screens/Blogs'; import Comments from './screens/Comments'; // create navigator const AppNavigator = createStackNavigator({ BlogsScreen: { screen: Blogs }, CommentsScreen: { screen: Comments } }); // create container, which houses the navigator const AppContainer = createAppContainer(AppNavigator); // Now AppContainer is the main component for React to render export default AppContainer; |
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import React, { Component } from "react"; import { StyleSheet, Text, View, AppRegistry, Image } from "react-native"; import AppContainer from "./AppContainer"; export default class App extends React.Component { constructor(props) { console.log('√ App.js - constructor'); super(props) this.state = { blogId: -1, } } assignBlogId = (newBlogId, callback) => { this.setState({blogId: newBlogId}); callback(); } assignAllComments = (comments) => { this.setState({allComments: comments}); } retrieveAllComments = () => { return this.state.allComments; } render() { return ( <AppContainer screenProps={ { currentBlogId: this.state.blogId, assignNewBlogId: this.assignBlogId, assignComments: this.assignAllComments, } } /> ); } |