Skip to content

Commit eaab8ee

Browse files
authored
re write with hooks and upgrade linters (#105)
rewrite with hooks 🚀
1 parent 881f0c8 commit eaab8ee

File tree

10 files changed

+1868
-2185
lines changed

10 files changed

+1868
-2185
lines changed

.eslintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
],
2525
"settings": {
2626
"react": {
27-
"version": "detect",
28-
},
27+
"version": "detect"
28+
}
2929
},
3030
"rules": {
3131
"react-native/no-raw-text": 0 // Avoid false positive, wait for fix

App/App.js

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
1-
import React, { Component } from 'react'
1+
import React from 'react'
22
import { Provider } from 'react-redux'
33
import { PersistGate } from 'redux-persist/lib/integration/react'
44
import createStore from 'App/Stores'
55
import RootScreen from './Containers/Root/RootScreen'
66

77
const { store, persistor } = createStore()
88

9-
export default class App extends Component {
10-
render() {
11-
return (
12-
/**
13-
* @see https://github.com/reduxjs/react-redux/blob/master/docs/api/Provider.md
14-
*/
15-
<Provider store={store}>
16-
{/**
17-
* PersistGate delays the rendering of the app's UI until the persisted state has been retrieved
18-
* and saved to redux.
19-
* The `loading` prop can be `null` or any react instance to show during loading (e.g. a splash screen),
20-
* for example `loading={<SplashScreen />}`.
21-
* @see https://github.com/rt2zz/redux-persist/blob/master/docs/PersistGate.md
22-
*/}
23-
<PersistGate loading={null} persistor={persistor}>
24-
<RootScreen />
25-
</PersistGate>
26-
</Provider>
27-
)
28-
}
29-
}
9+
const App = () => (
10+
/**
11+
* @see https://github.com/reduxjs/react-redux/blob/master/docs/api/Provider.md
12+
*/
13+
<Provider store={store}>
14+
{/**
15+
* PersistGate delays the rendering of the app's UI until the persisted state has been retrieved
16+
* and saved to redux.
17+
* The `loading` prop can be `null` or any react instance to show during loading (e.g. a splash screen),
18+
* for example `loading={<SplashScreen />}`.
19+
* @see https://github.com/rt2zz/redux-persist/blob/master/docs/PersistGate.md
20+
*/}
21+
<PersistGate loading={null} persistor={persistor}>
22+
<RootScreen />
23+
</PersistGate>
24+
</Provider>
25+
)
26+
27+
export default App
Lines changed: 51 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React from 'react'
1+
import React, { useEffect } from 'react'
22
import { Platform, Text, View, Button, ActivityIndicator, Image } from 'react-native'
3-
import { connect } from 'react-redux'
4-
import { PropTypes } from 'prop-types'
3+
import { useDispatch, useSelector } from 'react-redux'
54
import ExampleActions from 'App/Stores/Example/Actions'
65
import { liveInEurope } from 'App/Stores/Example/Selectors'
76
import Style from './ExampleScreenStyle'
@@ -13,85 +12,62 @@ import { ApplicationStyles, Helpers, Images, Metrics } from 'App/Theme'
1312
* This screen displays a little help message and informations about a fake user.
1413
* Feel free to remove it.
1514
*/
16-
1715
const instructions = Platform.select({
1816
ios: 'Press Cmd+R to reload,\nCmd+D or shake for dev menu.',
1917
android: 'Double tap R on your keyboard to reload,\nShake or press menu button for dev menu.',
2018
})
2119

22-
class ExampleScreen extends React.Component {
23-
componentDidMount() {
24-
this._fetchUser()
25-
}
20+
const ExampleScreen = () => {
21+
const dispatch = useDispatch()
2622

27-
render() {
28-
return (
29-
<View
30-
style={[
31-
Helpers.fill,
32-
Helpers.rowMain,
33-
Metrics.mediumHorizontalMargin,
34-
Metrics.mediumVerticalMargin,
35-
]}
36-
>
37-
{this.props.userIsLoading ? (
38-
<ActivityIndicator size="large" color="#0000ff" />
39-
) : (
40-
<View>
41-
<View style={Style.logoContainer}>
42-
<Image style={Helpers.fullSize} source={Images.logo} resizeMode={'contain'} />
43-
</View>
44-
<Text style={Style.text}>To get started, edit App.js</Text>
45-
<Text style={Style.instructions}>{instructions}</Text>
46-
{this.props.userErrorMessage ? (
47-
<Text style={Style.error}>{this.props.userErrorMessage}</Text>
48-
) : (
49-
<View>
50-
<Text style={Style.result}>
51-
{"I'm a fake user, my name is "}
52-
{this.props.user.name}
53-
</Text>
54-
<Text style={Style.result}>
55-
{this.props.liveInEurope ? 'I live in Europe !' : "I don't live in Europe."}
56-
</Text>
57-
</View>
58-
)}
59-
<Button
60-
style={ApplicationStyles.button}
61-
onPress={() => this._fetchUser()}
62-
title="Refresh"
63-
/>
64-
</View>
65-
)}
66-
</View>
67-
)
68-
}
23+
const user = useSelector((state) => state.example.user)
24+
const userIsLoading = useSelector((state) => state.example.userIsLoading)
25+
const userErrorMessage = useSelector((state) => state.example.userErrorMessage)
6926

70-
_fetchUser() {
71-
this.props.fetchUser()
72-
}
73-
}
27+
useEffect(() => {
28+
dispatch(ExampleActions.fetchUser())
29+
}, [])
7430

75-
ExampleScreen.propTypes = {
76-
user: PropTypes.object,
77-
userIsLoading: PropTypes.bool,
78-
userErrorMessage: PropTypes.string,
79-
fetchUser: PropTypes.func,
80-
liveInEurope: PropTypes.bool,
31+
return (
32+
<View
33+
style={[
34+
Helpers.fillCenter,
35+
Helpers.rowMain,
36+
Metrics.mediumHorizontalMargin,
37+
Metrics.mediumVerticalMargin,
38+
]}
39+
>
40+
{userIsLoading ? (
41+
<ActivityIndicator size="large" color="#0000ff" />
42+
) : (
43+
<View>
44+
<View style={Style.logoContainer}>
45+
<Image style={Helpers.fullSize} source={Images.logo} resizeMode={'contain'} />
46+
</View>
47+
<Text style={Style.text}>To get started, edit App.js</Text>
48+
<Text style={Style.instructions}>{instructions}</Text>
49+
{userErrorMessage ? (
50+
<Text style={Style.error}>{userErrorMessage}</Text>
51+
) : (
52+
<View>
53+
<Text style={Style.result}>
54+
{"I'm a fake user, my name is "}
55+
{user.name}
56+
</Text>
57+
<Text style={Style.result}>
58+
{liveInEurope ? 'I live in Europe !' : "I don't live in Europe."}
59+
</Text>
60+
</View>
61+
)}
62+
<Button
63+
style={ApplicationStyles.button}
64+
onPress={() => dispatch(ExampleActions.fetchUser())}
65+
title="Refresh"
66+
/>
67+
</View>
68+
)}
69+
</View>
70+
)
8171
}
8272

83-
const mapStateToProps = (state) => ({
84-
user: state.example.user,
85-
userIsLoading: state.example.userIsLoading,
86-
userErrorMessage: state.example.userErrorMessage,
87-
liveInEurope: liveInEurope(state),
88-
})
89-
90-
const mapDispatchToProps = (dispatch) => ({
91-
fetchUser: () => dispatch(ExampleActions.fetchUser()),
92-
})
93-
94-
export default connect(
95-
mapStateToProps,
96-
mapDispatchToProps
97-
)(ExampleScreen)
73+
export default ExampleScreen

App/Containers/Root/RootScreen.js

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,28 @@
1-
import React, { Component } from 'react'
1+
import React, { useEffect } from 'react'
22
import NavigationService from 'App/Services/NavigationService'
33
import AppNavigator from 'App/Navigators/AppNavigator'
44
import { View } from 'react-native'
5-
import { connect } from 'react-redux'
65
import StartupActions from 'App/Stores/Startup/Actions'
7-
import { PropTypes } from 'prop-types'
86
import { Helpers } from 'App/Theme'
7+
import { useDispatch } from 'react-redux'
98

10-
class RootScreen extends Component {
11-
componentDidMount() {
12-
// Run the startup saga when the application is starting
13-
this.props.startup()
14-
}
9+
const RootScreen = () => {
10+
const dispatch = useDispatch()
1511

16-
render() {
17-
return (
18-
<View style={Helpers.fill}>
19-
<AppNavigator
20-
// Initialize the NavigationService (see https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html)
21-
ref={(navigatorRef) => {
22-
NavigationService.setTopLevelNavigator(navigatorRef)
23-
}}
24-
/>
25-
</View>
26-
)
27-
}
28-
}
12+
useEffect(() => {
13+
dispatch(StartupActions.startup())
14+
}, [])
2915

30-
RootScreen.propTypes = {
31-
startup: PropTypes.func,
16+
return (
17+
<View style={Helpers.fill}>
18+
<AppNavigator
19+
// Initialize the NavigationService (see https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html)
20+
ref={(navigatorRef) => {
21+
NavigationService.setTopLevelNavigator(navigatorRef)
22+
}}
23+
/>
24+
</View>
25+
)
3226
}
3327

34-
const mapStateToProps = (state) => ({})
35-
36-
const mapDispatchToProps = (dispatch) => ({
37-
startup: () => dispatch(StartupActions.startup()),
38-
})
39-
40-
export default connect(
41-
mapStateToProps,
42-
mapDispatchToProps
43-
)(RootScreen)
28+
export default RootScreen

App/Containers/SplashScreen/SplashScreen.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import { Text, View } from 'react-native'
33
import styles from './SplashScreenStyle'
44
import { Helpers } from 'App/Theme'
55

6-
export default class SplashScreen extends React.Component {
7-
render() {
8-
return (
9-
<View style={[Helpers.fillRowCenter, styles.container]}>
10-
<View style={[Helpers.center, styles.logo]}>
11-
{/* You will probably want to insert your logo here */}
12-
<Text>LOGO</Text>
13-
</View>
14-
</View>
15-
)
16-
}
17-
}
6+
const SplashScreen = () => (
7+
<View style={[Helpers.fillRowCenter, styles.container]}>
8+
<View style={[Helpers.center, styles.logo]}>
9+
{/* You will probably want to insert your logo here */}
10+
<Text>LOGO</Text>
11+
</View>
12+
</View>
13+
)
14+
15+
export default SplashScreen

App/Services/UserService.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ const userApiClient = axios.create({
2828
function fetchUser() {
2929
// Simulate an error 50% of the time just for testing purposes
3030
if (Math.random() > 0.5) {
31-
return new Promise(function(resolve, reject) {
31+
return new Promise((resolve, reject) => {
3232
resolve(null)
3333
})
3434
}
3535

36-
let number = Math.floor(Math.random() / 0.1) + 1
36+
const number = Math.floor(Math.random() / 0.1) + 1
3737

3838
return userApiClient.get(number.toString()).then((response) => {
3939
if (in200s(response.status)) {

App/Stores/Example/Selectors.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ export const liveInEurope = (state) => {
1010
if (Object.entries(state.example.user).length <= 0) return null
1111

1212
// For this example, we imagine this cities are european cities
13-
let europeanCities = ['Gwenborough', 'Wisokyburgh', 'McKenziehaven', 'South Elvis', 'Roscoeview']
13+
const europeanCities = [
14+
'Gwenborough',
15+
'Wisokyburgh',
16+
'McKenziehaven',
17+
'South Elvis',
18+
'Roscoeview',
19+
]
1420

1521
return europeanCities.includes(state.example.user.address.city)
1622
}

ios/Podfile.lock

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ PODS:
217217
- React-cxxreact (= 0.61.5)
218218
- React-jsi (= 0.61.5)
219219
- ReactCommon/jscallinvoker (= 0.61.5)
220-
- RNGestureHandler (1.3.0):
220+
- RNGestureHandler (1.6.1):
221+
- React
222+
- RNScreens (2.7.0):
221223
- React
222224
- Yoga (1.14.0)
223225

@@ -250,6 +252,7 @@ DEPENDENCIES:
250252
- ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`)
251253
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
252254
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
255+
- RNScreens (from `../node_modules/react-native-screens`)
253256
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
254257

255258
SPEC REPOS:
@@ -307,6 +310,8 @@ EXTERNAL SOURCES:
307310
:path: "../node_modules/react-native/ReactCommon"
308311
RNGestureHandler:
309312
:path: "../node_modules/react-native-gesture-handler"
313+
RNScreens:
314+
:path: "../node_modules/react-native-screens"
310315
Yoga:
311316
:path: "../node_modules/react-native/ReactCommon/yoga"
312317

@@ -336,9 +341,10 @@ SPEC CHECKSUMS:
336341
React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe
337342
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
338343
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
339-
RNGestureHandler: 5329a942fce3d41c68b84c2c2276ce06a696d8b0
344+
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
345+
RNScreens: cf198f915f8a2bf163de94ca9f5bfc8d326c3706
340346
Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b
341347

342-
PODFILE CHECKSUM: 3d811d26fadf74812df3c538c7abf505a9be9900
348+
PODFILE CHECKSUM: 1aeb3204d81fb1938d1f1a04d0a3797595914ef3
343349

344-
COCOAPODS: 1.8.4
350+
COCOAPODS: 1.9.0

0 commit comments

Comments
 (0)