React Native 10
React Native 10
cd first_app
npm start
0_install
- first_app -
- node_modules
- package.json
- package-lock.json
- public
- src -
- App.css
- App.js
- index.css
- index.js
- reportWebVitals.js
- components -
- header.js
- footer.js
1_hello_react_app
- src
2_components
- src
3_props
- src
4_events
- src
5_state
- src
1
(5) React State Assignment
render() {
return (
<div>
<div>
<p> {this.state.name} </p>
</div>
<div>
name : <input onChange={this.setName} type="text" />
</div>
<button onClick={this.clickMe}> Click </button>
</div>
)
}
}
export default AboutUs;
2
Change App.js file.
import './App.css';
import AboutUs from './components/about.js';
function App() {
return (
<div className="App">
<header className="App-header">
<AboutUs />
</header>
</div>
);
}
cd 0_install/first_app
npm start
3
(6) React Life Cycle
constructor(props) {
super(props);
console.log('constructor call');
}
componentDidMount() {
console.log('componentDidMount call');
}
componentDidUpdate() {
console.log('componentDidUpdate call');
}
componentWillUpdate() {
console.log('componentWillUpdate call');
}
componentWillUnmount() {
console.log('componentWillUnmount call');
}
render() {
console.log('render call');
return (
...
)
}
}
cd 0_install/first_app
npm start
4
(7) React Conditional
Example 1
5
Change App.js file.
import './App.css';
import EvenOdd from './components/even_odd.js';
function App() {
return (
<div className="App">
<header className="App-header">
<EvenOdd />
</header>
</div>
);
}
Example 2
6
class Login extends Component {
state = {
isLogin: false,
username: '',
}
setUser = evt => {
this.state.username = evt.target.value;
}
clickLogin = evt => {
if (this.state.username == 'kyaw' && this.state.passwd == '123') {
this.setState({isLogin: true});
}
}
clickLogout = evt => {
this.setState({isLogin: false});
}
render() {
return (
<div>
{ this.state.isLogin ? (
<div>
<div>
Welcome home screen !
</div>
<div>
<button onClick={ this.clickLogout }> Logout </button>
</div>
</div>
):(
<div>
<div>
username: <input onChange={ this.setUser} type="text" />
</div>
<div>
<button onClick={ this.clickLogin }> Login </button>
</div>
</div>
)
}
</div>
)
}
}
export default Login;
7
(8) React Keys
render() {
const employees = ['aung aung', 'mg mg', 'kyaw kyaw', 'aye aye']
return (
<div>
{ employees.map(employee => {
return (
<div>
<h1> { employee } </h1>
</div>
)
})
}
</div>
)
}
}
8
Create component/new_home.js file.
render() {
const employees = [
{id: 1, name: 'aung aung'},
{id: 2, name: 'mg mg'},
{id: 3, name: 'kyaw kyaw'},
{id: 4, name: 'aye aye'}
]
return (
<div>
{ employees.map(employee => {
return (
<div key={employee.id}>
<h1> { employee.name } </h1>
</div>
)
})
}
</div>
)
}
}
9
(9) React Router
npm list
Run in browser -
localhost:3000/login
localhost:3000/home
localhost:3000/evenodd
10
(10) React Hooks
useState
function NewLogin() {
const [islogin, setlogin] = useState(false);
const [username, setusername] = useState("");
...
import Login from './new_login.js';
...
11
useEffect
function NewLogin() {
...
useEffect(() => {
// run after every rendering
if (islogin && username) {
console.log(username, 'logged in.');
}
});
username = aung
passwd == 321
username = aye
passwd == 456
12
useContext
return (
<BrowserRouter>
<Context.Provider value={app_name}>
<Routes>
...
</Routes>
</Context.Provider>
</BrowserRouter>
)
};
...
import { Context } from './new_menu.js';
...
return (
<div>
<Context.Consumer>
{ value => <span> { value } </span> }
</Context.Consumer>
{ islogin ? (
...
Add Context Consumer in new_home.js and even_odd.js and app_name change to Second App.
13
(11) React Styling
CSS Stylesheet
.Login {
background-color: blue;
}
...
import '../Login.css';
...
return (
<div className="Login">
<Context.Consumer>
...
Style Object
...
render() {
const myStyle = {
backgroundColor: "orange",
};
return (
<div style={myStyle}>
<Context.Consumer>
...
Inline Style
...
return (
<div style={{ backgroundColor: "green" }}>
<Context.Consumer>
...
14
Django
mkdir 4_django_react
py -0
./django2.2-venv/Script/activate
cd hrms-api
15
Application Programming Interface (API)
username: admin
email: [email protected]
password: superuser
hrms-api/api/models.py
16
Django Restful Framework
2) Register in setting.py
INSTALLED_APPS = [
...
'django.contrib.staticfiles',
'rest_framework',
'api',
]
hrms-api/api/serializers.py
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = EmployeeModel
fields = ['id', 'name', 'phone', 'address']
4) Edit views.py.
hrms-api/api/views.py
class EmployeeViewSet(viewsets.ModelViewSet):
serializer_class = EmployeeSerializer
queryset = EmployeeModel.objects.all()
17
5) Creat new urls.py
hrms-api/api/urls.py
router = routers.DefaultRouter()
router.register('employees', EmployeeViewSet)
urlpatterns = [
path('', include(router.urls))
]
hrms-api/hrms/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls'))
]
{
"id": 2,
"name": "Mg Mg",
"phone": "09787897878",
"address": "Mandalay"
}
18
GET (Read employee)
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"id": 1,
"name": "Kyaw Kyaw",
"phone": "09383838",
"address": "Yangon"
}
]
HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"id": 2,
"name": "Maung Maung",
"phone": "09787897878",
"address": "Mandalay"
}
19
Auth Token
1) Register in setting.py
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
'api',
]
5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a
hrms-api/hrms/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
path('auth/', obtain_auth_token)
]
Return Result
{"token":"5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a"}
20
Permission IsAuthenticated
1) Edit setting.py
...
WSGI_APPLICATION = 'hrms.wsgi.application'
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
...
2) Edit views.py
class EmployeeViewSet(viewsets.ModelViewSet):
serializer_class = EmployeeSerializer
queryset = EmployeeModel.objects.all()
authentication_classes = (TokenAuthentication,)
username = admin
password = superuser
Return Result
{
"detail": "Authentication credentials were not provided."
}
21
4) Include headers.
Headers
Return Result
[
{
"id": 1,
"name": "Kyaw Kyaw Kwa",
"phone": "09383838",
"address": "Yangon"
}
]
22
Django React
project structure
- hrms-web -
- node_modules
- package.json
- package-lock.json
- public
- src -
- App.css
- App.js
- index.css
- index.js
- reportWebVitals.js
- components -
- home.js
- login.js
- menu.js
home.js
})
}
</div>
)
}
}
23
menu.js
App.js
import './App.css';
import Menu from './components/menu.js';
function App() {
return (
<div className="App">
<header className="App-header">
<Menu />
</header>
</div>
);
}
Test url
localhost:3000/home
localhost:3000/login
24
(1) Using Fetch Method
home.js
componentDidMount(){
fetch('http://127.0.0.1:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a'
}
})
.then( resp => resp.json())
.then( res => console.log(res))
.catch( error => console.log(error))
}
render() {
const employees = ['aung aung', 'mg mg', 'kyaw kyaw', 'aye aye']
return (
<div>
{ employees.map(employee => {
return (
<div>
<h1> { employee } </h1>
</div>
)
})
}
</div>
)
}
}
25
Key Error
Update home.js
render() {
const employees = ['aung aung', 'mg mg', 'kyaw kyaw', 'aye aye']
return (
<div>
{ employees.map(employee => {
return (
<div key= { employee }>
<h1> { employee } </h1>
</div>
)
})
}
</div>
)
}
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at
http://127.0.0.1:8000/api/employees/. (Reason: CORS header ‘Access-Control-Allow-Origin’
missing). Status code: 401.
Install django-cors-headers
Change hrms-api/hrms/settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
...
]
CORS_ORIGIN_WHITELIST = (
'localhost:3000'
)
26
Update return data into state
Change home.js
state = {
employees: []
}
componentDidMount(){
fetch('http://127.0.0.1:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a'
}
})
.then( resp => resp.json())
.then( res => this.setState({ employees: res }))
.catch( error => console.log(error))
}
render() {
//const employees = ['aung aung', 'mg mg', 'kyaw kyaw', 'aye aye']
return (
<div>
{
this.state.employees.map(employee => {
return (
<div key={ employee.id }>
<h1> { employee.name } </h1>
</div>
)
})
}
</div>
)
}
}
27
(2) List View
project structure
- hrms-web -
...
- public
- src -
- App.css
- App.js
...
- components -
- home.js
- login.js
- menu.js
- employees
- detail.js
- list.js
- form.js
Change list.js
render() {
return (
<div>
<h1> List View </h1>
{
this.props.employees.map(employee => {
return (
<div key={ employee.id }>
<h3> { employee.name } </h3>
</div>
)
})
}
</div>
)
}
}
28
Change home.js
state = {
employees: []
}
componentDidMount(){
...
}
render() {
return (
<div>
<h1> HRMS </h1>
<div>
<EmployeeList employees={ this.state.employees }/>
</div>
</div>
)
}
}
29
(3) Detail View
detail.js
render() {
return (
<div>
<h1> Detail View </h1>
</div>
)
}
}
home.js
state = {
employees: []
}
componentDidMount(){
...
}
render() {
return (
<div>
<h1> HRMS </h1>
<div>
<EmployeeList employees={ this.state.employees }/>
<EmployeeDetail />
</div>
</div>
)
}
}
30
Create src/Home.css
Home.css
.Header {
display: grid;
grid-template-columns: 1fr 1fr;
text-align: left;
grid-gap: 100px;
}
import '../Home.css';
31
(3) List Item Click
home.js
state = {
employees: []
}
componentDidMount(){
...
}
render() {
return (
<div>
<h1> HRMS </h1>
<div className="Header">
<EmployeeList employees={this.state.employees}
employeeClicked={this.employeeClicked}/>
<EmployeeDetail />
</div>
</div>
)
}
}
32
list.js
render() {
return (
<div>
<h1> Employee List </h1>
{
his.props.employees.map(employee => {
return (
<div key={ employee.id }>
<h3
onClick={this.employeeClicked(employee)}>
{ employee.name }
</h3>
</div>
)
})
}
</div>
)
}
}
console result
Employee Clicked
Object { id: 1, name: "Kyaw Kyaw", phone: "09383838", address: "Yangon" }
home.js:28
Employee Clicked
Object { id: 4, name: "Aung Aung", phone: "09373737373", address: "Mandalay" }
home.js:28
33
(4) Connect List View with Detail View
home.js
state = {
employees: [],
selectedEmployee: null
}
render() {
return (
...
<EmployeeDetail employee={ this.state.selectedEmployee } />
...
)
}
detail.js
render() {
return (
<div>
<h1> Detail View </h1>
<div>
<h3> {employee.name} </h3>
<p> {employee.phone} </p>
<p> {employee.address} </p>
</div>
</div>
)
}
}
34
Uncaught TypeError: employee is null
Update home.js
{
this.state.selectedEmployee
?
<EmployeeDetail employee={ this.state.selectedEmployee } />
:
null
}
Change form.js
render() {
return (
<div>
<h1> Form View </h1>
</div>
)
}
}
35
Change home.js
componentDidMount(){
...
}
addNewClicked = () => {
console.log("Add New Click");
this.setState({ view_type: 'create'});
};
render() {
return (
<div>
...
<div className="Header">
{
this.state.view_type == 'create'
? <EmployeeForm/> : null
}
{
this.state.view_type == 'detail'
? <EmployeeDetail
employee={ this.state.selectedEmployee } />
: null
}
</div>
<div className="Footer">
<button onClick={this.addNewClicked}>Add New</button>
</div>
</div>
)
}
}
36
Add new css class at Home.css
.Footer {
text-align: left;
}
Change form.js
render() {
return (
<div>
<h1> Form View </h1>
<div>
<span> Name </span> <br/>
<input name="name" type="text" /> <br/>
<span> Phone </span> <br/>
<input name="phone" type="text" /> <br/>
<span> Address </span> <br/>
<input name="address" type="text" /> <br/>
<button onClick={this.save}> Save </button>
</div>
</div>
)
}
}
37
(6) Form Save
Change form.js
state = {
editedEmployee: {'name': '', 'phone': '', 'address': ''}
}
save = () => {
console.log('save click');
fetch('http://127.0.0.1:8000/api/employees/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a'
},
body: JSON.stringify(this.state.editedEmployee)
}).then( resp => resp.json())
.then( res => console.log(res))
.catch( error => console.log(error))
}
render() {
return (
<div>
<h1> Form View </h1>
<div>
<span> Name </span> <br/>
<input name="name" type="text" onChange={this.inputChanged}/> <br/>
...
</div>
</div>
)
}
}
38
(7) Form Update
public/index.html
List.css
.List {
display: grid;
grid-template-columns: 1fr auto auto;
}
list.js
render() {
return (
<div>
<h1> Employee List </h1>
{
this.props.employees.map(employee => {
return (
<div key={employee.id} className="List">
...
<FontAwesome name="edit"
onClick={this.updateClicked(employee)}/>
</div>
)
})
}
</div>
...
39
Change home.js
addNewClicked = () => {
console.log("Add New Click");
let newemployee = {'name': '', 'phone': '', 'address': ''};
this.setState({selectedEmployee: newemployee, view_type: 'create'});
};
render() {
return (
<div>
<h1> HRMS </h1>
<div className="Header">
<EmployeeList employees={this.state.employees}
employeeClicked={this.employeeClicked}
updateClicked={this.updateClicked}/>
{
this.state.view_type == 'create'
|| this.state.view_type == 'update'
?
<EmployeeForm . . ./>
:
null
}
...
</div>
...
40
Change form.js
state = {
editedEmployee: null
}
save = () => {
...
}
update = () => {
console.log('update click');
fetch(`http://127.0.0.1:8000/api/employees/${this.props.employee.id}/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c28a'
},
body: JSON.stringify(
this.state.editedEmployee
)
}).then( resp => resp.json())
.then( res => console.log(res))
.catch( error => console.log(error))
}
render() {
return (
<div>
<h1> Form View </h1>
<div>
<input name="name" type="text" value={this.props.employee.name}
onChange={this.inputChanged}/> <br/>
...
<button onClick={this.save}> Save </button>
<button onClick={this.update}> Update </button>
</div>
</div>
...
41
(8) Delete
list.js
...
...
(9) Reload
home.js
reload = (employee, method) => {
if (method == 'save') {
this.setState({employees: [...this.state.employees, employee]});
} else if (method == 'update') {
this.setState({view_type: ''});
} else if (method == 'delete') {
const employees = this.state.employees.filter( emp => emp.id !==
employee.id);
this.setState({employees: employees});
}
}
Change form.js and list.js under save, update and delete function.
save = () => {
fetch('http://127.0.0.1:8000/api/employees/', {
...
}).then( resp => resp.json())
.then( res => this.props.reload(res, 'save'))
.catch( error => console.log(error))
}
42
(10) Login
Change login.js
clickLogin = () => {
fetch('http://127.0.0.1:8000/auth/', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(this.state.user)
})
.then( resp => resp.json())
.then( res => {
console.log(res.token);
if (res.token) {
window.location.href = "/home";
} else {
alert("Username & Password Invalid !");
}
}).catch( error => console.log(error))
}
render() {
return (
<div className="Login">
<div>
<div>
username : <input name="username"
onChange={ this.inputChanged } type="text" />
</div>
...
</div>
</div>
)
}
}
export default Login;
43
(11) React Cookie
menu.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Login from './login.js';
import Home from './home.js';
import { CookiesProvider } from "react-cookie";
login.js
import React, { Component } from 'react';
import { withCookies } from "react-cookie";
44
home.js
componentDidMount(){
fetch('http://127.0.0.1:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${this.state.token}`
}
})
.then( resp => resp.json())
.then( res => this.setState({employees: res}))
.catch( error => console.log(error))
}
...
render() {
return (
<div>
<h1> HRMS </h1>
<div className="Header">
<EmployeeList employees={ this.state.employees }
employeeClicked={this.employeeClicked} updateClicked={this.updateClicked}
reload={this.reload} token={this.state.token}/>
...
</div>
)
}
}
45
form.js
...
save = () => {
console.log('save click');
fetch('http://127.0.0.1:8000/api/employees/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${this.props.token}`
},
body: JSON.stringify(this.state.editedEmployee)
}).then( resp => resp.json())
.then( res => this.props.reload(res, 'save'))
.catch( error => console.log(error))
}
update = () => {
console.log('update click');
fetch(`http://127.0.0.1:8000/api/employees/${this.props.employee.id}/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${this.props.token}`
},
body: JSON.stringify(
this.state.editedEmployee
)
}).then( resp => resp.json())
.then( res => this.props.reload(res, 'update'))
.catch( error => console.log(error))
}
render() {
...
}
}
46
Expo
Create new first_app/components folder and Create header.js and footer.js under components folder.
project structure
- first_app -
- node_modules
- assets
- babel.config.js
- package.json
- package-lock.json
- App.js
- app.json
- components -
- header.js
- footer.js
(1) Components
header.js
function Header() {
return (
<View>
<Text> Header </Text>
</View>
);
}
export { Header };
47
footer.js
App.js
48
(2) Props
App.js
header.js
function Header(props) {
return (
<View>
<Text> { props.message } </Text>
<Text> Our { props.name } page </Text>
</View>
);
}
export { Header };
footer.js
49
(3) Events
App.js
function showTesting() {
Alert.alert('you click testing !');
}
...
header.js
function Header(props) {
return (
<View>
<Text> { props.message } </Text>
<Text onPress={ props.popup }> Our { props.name } page </Text>
</View>
);
}
export { Header };
50
footer.js
logConsole() {
Alert.alert('you typed in footer ...');
}
render() {
return (
<View>
<Text> { this.props.address } </Text>
<TextInput onChangeText={ this.logConsole } />
</View>
);
}
}
51
(4) State
footer.js
state = {
name: 'Aung Aung'
}
logConsole() {
Alert.alert('you typed in footer ...');
}
showName = () => {
Alert.alert("You typed " + this.state.name);
}
render() {
return (
<View>
<Text> { this.props.address } </Text>
<TextInput onChangeText={ this.logConsole } />
<TextInput onChangeText={ this.setName }
style={{ backgroundColor: 'orange'}}/>
<Button onPress={ this.showName } title="Click Me"/>
</View>
);
}
}
52
header.js
function Header(props) {
return (
<View>
<Text> { props.message } </Text>
<Text onPress={ props.popup }> Our { props.name } page </Text>
<TextInput onChangeText={(name) => setName(name)}
style={{ backgroundColor: 'gray'}}/>
<Button onPress={() => alert("You typed" + name)} title="Click Me"/>
</View>
);
}
export { Header };
53
(5) Flat List
function List() {
const clickEmployee = (item) => {
Alert.alert("you clicked " + item.name);
}
return (
<View>
<FlatList
data={[
{name: 'Aung Aung'}, {name: 'Mg Mg'}, {name: 'Kyaw Kyaw'}
]}
renderItem={({item}) => (
<Text onPress={() => clickEmployee(item)}>
<View>
<Text >{item.name}</Text>
</View>
</Text>
)}
/>
</View>
);
}
export default List;
54
(6) Navigation
npm install
react-navigation
react-navigation-stack
react-native-gesture-handler
react-native-safe-area-context
function Detail() {
return (
<View>
<Text> Detail Screen </Text>
</View>
);
}
Update App.js
55
To click one screen to another screen.
list.js
function List(props) {
return (
<View>
<FlatList
...
/>
<Button
title="Go to Detail"
onPress={() => props.navigation.navigate('Detail')}
/>
</View>
);
}
list.js
function List(props) {
return (
<View>
...
</View>
);
}
56
Update detail.js
function Detail(props) {
return (
<View>
<Text> Detail Screen </Text>
<Text> Name: {name} </Text>
</View>
);
}
detail.js
function Detail(props) {
const name = props.navigation.getParam('name', '');
return (
...
);
}
Detail.navigationOptions = {
title: "Detail Screen",
headerStyle: {
backgroundColor: 'orange'
}
}
57
(7) Styles
login.js
function Login() {
return (
<View style={styles.container}>
<Image style={styles.image} source={require("../assets/logo.png")} />
<View style={styles.inputView}>
<TextInput
style={styles.inputText}
placeholder="Username"
/>
</View>
<View style={styles.inputView}>
<TextInput
style={styles.inputText}
placeholder="Password"
secureTextEntry={true}
/>
</View>
<TouchableOpacity>
<Text style={styles.signup}> Create New Account ?</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.login}>
<Text> Login </Text>
</TouchableOpacity>
</View>
);
}
58
image: {
marginBottom: 40,
width: 100,
height: 100
},
inputView: {
backgroundColor: "#FFC7A1",
borderRadius: 30,
width: "70%",
height: 45,
marginBottom: 20,
},
inputText: {
height: 50,
padding: 10,
marginLeft: 20,
},
signup: {
height: 20,
marginBottom: 20,
},
login: {
width: "70%",
height: 50,
alignItems: "center",
justifyContent: "center",
marginTop: 40,
backgroundColor: "#FF7D26",
},
});
59
(8) Android or IOS Platform
login.android.js
function Login() {
return (
<View style={styles.container}>
...
</View>
);
}
...
inputView: {
backgroundColor: Platform.OS == 'android' ? "#FFC7A1" : "blue",
borderRadius: 30,
width: "70%",
height: 45,
marginBottom: 20,
},
...
});
60
(9) Icon and Splash Screen
Change app.json
{
"expo": {
"name": "fist_app",
"slug": "fist_app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/my_logo.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/my_splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
61
React Native
mkdir android/app/src/main/assets
Bundle js
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output
android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
cd android
gradlew assembleDebug
jdk.java.net/archive/
cd react_native\hrmsmobile\android\app\build\outputs\apk\debug
python -m http.server 8007
62
Expo Project For Test
npm install
react-navigation
react-navigation-stack
react-native-gesture-handler
react-native-safe-area-context
Change App.js
63
Change login.js
Change list.js
</View>
);
}
}
List.navigationOptions = {
title: "Home Screen",
headerStyle: {
backgroundColor: '#714B67'
},
headerTintColor: '#fff',
}
64
flex: 1,
}
})
Change form.js
render() {
return (
<View style={styles.container}>
<View style={{ marginBottom:20, height: 100,
alignItems:"center", justifyContent: "center"}}>
<Text style={{ fontSize: 20, fontWeight: 'bold',
marginBottom: 20}}> Employee Form </Text>
</View>
</View>
);
}
}
Form.navigationOptions = {
title: "Form Screen",
headerStyle: {
backgroundColor: 'green'
},
headerTintColor: '#fff',
}
65
Change detail.js
render() {
return (
<View style={styles.container}>
<View style={{ marginBottom:20, height: 100,
alignItems:"center", justifyContent: "center"}}>
<Text style={{fontSize:20, fontWeight:'bold'}}> Employee
Detail </Text>
</View>
</View>
);
}
}
Detail.navigationOptions = {
title: "Detail Screen",
headerStyle: {
backgroundColor: 'orange'
},
headerTintColor: '#fff'
}
66
(2) Using Fetch Method
list.js
componentDidMount() {
console.log('componentDidMount call');
fetch('http://192.168.99.175:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e8'
}
})
.then( resp => resp.json())
.then( res => console.log(res))
.catch( error => console.log(error))
}
list.js
state = {
employees: []
}
componentDidMount() {
console.log('componentDidMount call');
fetch('http://192.168.99.175:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c2'
}
})
.then( resp => resp.json())
.then( res => this.setState({employees: res}))
.catch( error => console.log(error))
}
67
render() {
return (
<View style={styles.container}>
<View >
. . .
</View>
<FlatList
data={this.state.employees}
renderItem={({item, index}) => (
<Text style={[
{ padding: 10, fontSize: 18, height:
44,backgroundColor: 'white', flex: 1 },
index % 2 == 0 ? { backgroundColor: '#D3D3D3' } : {
backgroundColor: 'white' }
]}>
{item.name}
</Text>
)}
/>
</View>
);
}
}
List.navigationOptions = {
title: "Home Screen",
headerStyle: {
backgroundColor: '#714B67'
},
headerTintColor: '#fff',
}
68
(4) Events
list.js
detail.js
render() {
employee = this.props.navigation.getParam('employee', '');
return (
<View style={styles.container}>
<View> </View>
<View style={{ marginLeft:20, alignItems: 'flex-start' }}>
<Text> Name: { employee.name } </Text>
<Text> Phone: { employee.phone } </Text>
<Text> Address: { employee.address } </Text>
</View>
<View style={{ marginTop:50, alignItems:"center"}}>
<View style={{ width: '80%'}}>
<Button title="Update"
onPress={() =>
this.props.navigation.navigate('Form',{employee: employee, view_type: false })}
/>
<Text />
<Button title="Delete"
onPress={this.deleteClicked} />
<Text />
<Button title="Go Home" onPress={() =>
this.props.navigation.navigate('List')} />
</View>
</View>
</View>
69
(5) Floating Action Button
list.js
componentDidMount() {
. . .
}
addNewClicked = () => {
console.log("Add New Click");
let newemployee = {
'name': '',
'phone': '',
'address': ''
};
this.props.navigation.navigate('Form', { employee: newemployee,
view_type: true });
}
render() {
return (
<View style={styles.container}>
<View >
</View>
<FlatList
. . .
/>
<FloatingAction onPressMain={this.addNewClicked}/>
</View>
);
}
}
70
form.js
state = {
editedEmployee: null
}
save = () => {
console.log('save click');
}
update = () => {
console.log('update click');
}
render() {
return (
<View style={styles.container}>
<View >
. . .
</View>
<TextInput
style={styles.inputText}
onChangeText={value => this.inputChanged('name', value)}
/>
<TextInput
style={styles.inputText}
onChangeText={value => this.inputChanged('phone', value)}
/>
<TextInput
style={styles.inputText}
onChangeText={value => this.inputChanged('address', value)}
/>
71
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
},
inputText: {
height: 50,
padding: 10,
height: 45,
width: "80%",
borderRadius: 10,
marginBottom: 20,
borderColor: 'blue',
borderWidth: 1
},
});
form.js
render() {
employee = this.props.navigation.getParam('employee', '');
view_type = this.props.navigation.getParam('view_type', '');
return (
<View style={styles.container}>
<TextInput
style={styles.inputText}
value={employee.name}
onChangeText={value => this.inputChanged('name', value)}
/>
<TextInput
style={styles.inputText}
value={employee.phone}
onChangeText={value => this.inputChanged('phone', value)}
/>
<TextInput
style={styles.inputText}
value={employee.address}
onChangeText={value => this.inputChanged('address', value)}
/>
72
(7) Login View
login.js
state = {
user: {
username: '',
password: ''
},
}
clickLogin = () => {
console.log('clickLogin call');
}
render() {
return (
<View style={styles.container}>
<Image style={styles.image} source={require("../assets/icon.png")} />
<TextInput
style={styles.inputText}
placeholder="Username"
onChangeText={value => this.inputChanged('username', value)}
/>
<TextInput
style={styles.inputText}
placeholder="Password"
secureTextEntry={true}
onChangeText={value => this.inputChanged('password', value)}
/>
73
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
image: {
marginBottom: 40,
width: 100,
height: 100
},
inputText: {
height: 50,
padding: 10,
height: 45,
width: "80%",
borderRadius: 10,
marginBottom: 20,
borderColor: '#714B67',
borderWidth: 1
},
signup: {
height: 20,
marginBottom: 20,
},
login: {
width: "70%",
height: 50,
alignItems: "center",
justifyContent: "center",
marginTop: 40,
backgroundColor: "#714B67",
},
});
clickLogin = () => {
console.log('clickLogin call');
fetch('http://192.168.99.175:8000/auth/', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(this.state.user)
})
.then( resp => resp.json())
.then( res => {
console.log(res.token);
if (res.token) {
this.props.navigation.navigate('List');
} else {
Alert.alert("Username & Password Invalid !");
}
}).catch( error => console.log(error))
}
74
(8) Save, Update and Delete Function
detail.js
deleteClicked = () => {
console.log('delete click');
employee = this.props.navigation.getParam('employee', '');
fetch(`http://192.168.99.175:8000/api/employees/${employee.id}/`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c2'
}
})
.then( res => this.props.navigation.navigate('List'))
.catch( error => console.log(error))
}
form.js
save = () => {
console.log('save click');
fetch('http://192.168.99.175:8000/api/employees/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c2'
},
body: JSON.stringify(this.state.editedEmployee)
}).then( resp => resp.json())
.then( res => this.props.navigation.navigate('Detail', {
employee: this.state.editedEmployee
})
)
.catch( error => console.log(error))
}
update = () => {
console.log('update click');
employee = this.props.navigation.getParam('employee', '');
fetch(`http://192.168.99.175:8000/api/employees/${employee.id}/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 5bfc020cdc3bbe1f3e399fe2c5727c6c7e85c2'
},
body: JSON.stringify(
this.state.editedEmployee
)
}).then( resp => resp.json())
.then( res => this.props.navigation.navigate('Detail', {
employee: this.state.editedEmployee
}))
.catch( error => console.log(error))
}
75
(9) Reload Flat List
list.js
onRefresh = () => {
this.setState({ isRefreshing: true});
this.componentDidMount();
this.setState({ isRefreshing: false});
}
componentDidMount() {
addNewClicked = () => {
render() {
return (
<View style={styles.container}>
<View >
</View>
<FlatList
data={this.state.employees}
renderItem={ . . . }
onRefresh={this.onRefresh}
refreshing={this.state.isRefreshing}
/>
<FloatingAction onPressMain={this.addNewClicked}/>
</View>
);
}
}
76
(10) Async Storage
npm i @react-native-async-storage/async-storage
state = {
}
clickLogin = () => {
console.log('clickLogin call');
fetch('http://192.168.99.175:8000/auth/', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(this.state.user)
})
.then( resp => resp.json())
.then( res => {
console.log(res.token);
AsyncStorage.setItem('hrms-token', res.token);
if (res.token) {
this.props.navigation.navigate('List');
} else {
Alert.alert("Username & Password Invalid !");
}
}).catch( error => console.log(error))
}
77
Async getItem from list.js
token = null;
state = {
employees: [],
isRefreshing: false
}
onRefresh = () => {
this.setState({ isRefreshing: true});
this.componentDidMount();
this.setState({ isRefreshing: false});
}
async componentDidMount() {
console.log('componentDidMount call');
token = await AsyncStorage.getItem('hrms-token');
fetch('http://192.168.99.175:8000/api/employees/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${token}`
}
})
.then( resp => resp.json())
.then( res => this.setState({employees: res}))
.catch( error => console.log(error))
}
addNewClicked = () => {
console.log("Add New Click");
this.props.navigation.navigate('Form', { employee: newemployee,
view_type: true, token: token });
}
78
detail.js
token = null;
deleteClicked = () => {
console.log('delete click');
token = this.props.navigation.getParam('token', '');
employee = this.props.navigation.getParam('employee', '');
fetch(`http://192.168.99.175:8000/api/employees/${employee.id}/`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${token}`
}
})
.then( res => this.props.navigation.navigate('List'))
.catch( error => console.log(error))
}
render() {
employee = this.props.navigation.getParam('employee', '');
return (
<View style={styles.container}>
<View >
</View>
<View >
</View>
<View style={{ marginTop:50, alignItems:"center"}}>
<View style={{ width: '80%'}}>
<Button title="Update"
onPress={() =>
this.props.navigation.navigate('Form', { employee: employee, view_type: false,
token: token })}
/>
<Text />
<Button title="Delete"
onPress={this.deleteClicked} />
<Text />
<Button title="Go Home" onPress={() =>
this.props.navigation.navigate('List')} />
</View>
</View>
</View>
);
}
}
79
form.js
state = {
editedEmployee: null
}
save = () => {
console.log('save click');
token = this.props.navigation.getParam('token', '');
fetch('http://192.168.99.175:8000/api/employees/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${token}`
},
body: JSON.stringify(this.state.editedEmployee)
}).then( resp => resp.json())
.then( res => this.props.navigation.navigate('Detail', {
employee: this.state.editedEmployee
})
)
.catch( error => console.log(error))
}
update = () => {
console.log('update click');
token = this.props.navigation.getParam('token', '');
employee = this.props.navigation.getParam('employee', '');
fetch(`http://192.168.99.175:8000/api/employees/${employee.id}/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${token}`
},
body: JSON.stringify(
this.state.editedEmployee
)
}).then( resp => resp.json())
.then( res => this.props.navigation.navigate('Detail', {
employee: this.state.editedEmployee
}))
.catch( error => console.log(error))
}
});
80
APK Export Error
(1) RNScreen Error
npm install react-native-screens
npm install
react-native-gesture-handler
react-native-reanimated
react-native-safe-area-context
react-native-screens
react-navigation
react-navigation-drawer
react-navigation-stack
react-native-vector-icons
Edit hrms-mobile/babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin',
],
};
};
Edit hrms-mobile/node_modules/react-navigation-drawer/lib/module/views/Drawer.js
Edit line 17
interpolate => interpolateNode
Edit line 334
interpolate => interpolateNode
81
Find complete source code at hrms-mobile-with-drawer.zip > complete_src folder > App.js
//employees
import List from './components/employees/list';
import Detail from './components/employees/detail';
import Form from './components/employees/form';
82
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
}
);
83