React Native Workshop - React Alicante
-
Upload
ignacio-martin -
Category
Software
-
view
616 -
download
5
Transcript of React Native Workshop - React Alicante
Nacho Martin
I write code at Limenius.
We build tailor-made projects, and provide consultancy and formation.
We are very happy with React and React Native.
Roadmap:What is React Native Starting a project Working with Styles Layout Lists Navigation Networking Touching the native side
Fundamental premise of React
Give me a state and a render() method that depends on it and forget about how and when to render.*
Fundamental premise of React
Give me a state and a render() method that depends on it and forget about how and when to render.*
* Unless you want more control.
render() { return ( <div className="App"> <button onClick={this.tick}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ) }
render() { return ( <div className="App"> <button onClick={this.tick}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ) }
render() { return ( <View style={…}> <Button onPress={this.tick}>Click me!</Button> <Text>Clicks: {this.state.count}</Text> </View> ) }
render() { return ( <div className="App"> <button onClick={this.tick}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ) }
render() { return ( <View style={…}> <Button onPress={this.tick}>Click me!</Button> <Text>Clicks: {this.state.count}</Text> </View> ) }
render() { return ( <div className="App"> <button onClick={this.tick}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ) }
render() { return ( <View style={…}> <Button onPress={this.tick}>Click me!</Button> <Text>Clicks: {this.state.count}</Text> </View> ) }
React Native
How is this possible
Reconciliation
Determines what parts of the tree have changed
Rendering
Actually updates the app
How is this possible
Reconciliation
Determines what parts of the tree have changed
Rendering
Actually updates the app
We can have several renderers
React targetsMain
react-dom react-native
Web iOS android
But also
react-art react-canvas react-three ReactLibertyreact-worker-dom
React targetsMain
react-dom react-native
Web iOS android
But also
react-art react-canvas react-three ReactLibertyreact-worker-dom
react-konsul raxreact-native react-blessedreact-tvml
React targetsMain
react-dom react-native
Web iOS android
But also
react-art react-canvas react-three ReactLibertyreact-worker-dom
react-konsul raxreact-native react-blessedreact-tvml
React-GLreact-vr react-hardware react-fs-renderer react-x11
React targetsMain
react-dom react-native
Web iOS android
But also
react-art react-canvas react-three ReactLibertyreact-worker-dom
react-konsul raxreact-native react-blessedreact-tvml
React-GLreact-vr react-hardware react-fs-renderer react-x11
redocx react-titanium React-Gibbon react-pdf react-test-renderer
React targetsMain
react-dom react-native
Web iOS android
But also
react-art react-canvas react-three ReactLibertyreact-worker-dom
react-konsul raxreact-native react-blessedreact-tvml
React-GLreact-vr react-hardware react-fs-renderer react-x11
redocx react-titanium React-Gibbon react-pdf react-test-renderer
ink react-sketchapp
How Native is React Native?
JS Thread Main Thread
UI manipulation with native components
Business logic & Description of what
components to render
How Native is React Native?
JS Thread Main Thread
UI manipulation with native components
Business logic & Description of what
components to render Bridge
How much code can we reuse?
Tip: if you develop in one platform, try it in the other from time to time
70%? 80%? 90%?
Option 1: create-react-native-app
$ npm install -g create-react-native-app
$ create-react-native-app AwesomeProject
Option 1: create-react-native-app
Only JS, no iOS or Android code (outside node_modules)
If you want to modify native code, $ npm run eject
Uses the Expo app to test in real device
Meant to have a quick way of trying react-native
Option 2: react-native init
Complete project with native code
More control
Needed to use things like CodePush
Doesn’t need external tools to publish to the store
git clone https://github.com/Limenius/workshop-react-native.git
You are supposed to have done this
🙏
And then yarn install
Play around
Open app/App.js with an editor
<Text style={styles.welcome}>Hi there!</Text>Change the text in
Try nesting <Text> <Text style={styles.welcome}>Hi there!</Text> Amigo</Text>
Try changing some styles
welcome: { fontSize: 100, textAlign: 'center', margin: 10,},
Try placing a console.log(‘hi’) before return(… and see it in Chrome dev tools
Familiarize with errorsWhat happens if we…
remove a closing tag (</View>)
<View style={styles.container}> Hi there!</View>
put text not wrapped in <Text/>
try to comment a JSX line with //return ( <View style={styles.container}> <Text style={styles.welcome}>Hi there!</Text> </View> <View/>)
have two root elements
use wrong properties for styles ( rename flex -> flexo )
remove the words export default
Exercise: Build new components
Can you build a new component combining others? Ideas: Image with footer (<Text/>), two buttons that display different alerts
Can you pass props to that component? Ideas: Pass the text of the footer with props, pass also the image, pass the titles of the buttons
Can your build a component with local state? Ideas: Modify the counter to have a “minus 1” button
No CSS. Everything is JS<View style={{ borderLeftColor: Colors.accent, borderLeftWidth: 9, backgroundColor: Colors.backgroundSection, padding: 18, paddingVertical: 9,}}>
No class No dimensions in pixels No things like padding: 19 9 3 1 camelCased
Use constants
StyleSheet
<View style={Styles.headline}>
const Styles = StyleSheet.create({ headline: { borderLeftColor: Colors.accent, borderLeftWidth: 9, backgroundColor: Colors.backgroundSection, paddingLeft: 18, paddingRight: 18, paddingTop: 9, paddingBottom: 9, },})
Combination
<View style={[Styles.headline, {backgroundColor: 'red'}]}>
const Styles = StyleSheet.create({ headline: { borderLeftColor: Colors.accent, borderLeftWidth: 9, paddingLeft: 18, paddingRight: 18, paddingTop: 9, paddingBottom: 9, },})
components/MovieHeader.js
height: 210
fontWeight: ‘bold’fontSize: FontSizes.LargeTitle48x48, roundedbackgroundColor: Colors.highlightcolor: Colors.textcolor: Colors.textfontWeight: ‘bold’
border: left, size 9, Colors.accentpadding: 9, 18backgroundColor: Colors.backgroundSection
Exercise 1
84x84
Colors.text, bold
Container has: border at bottom size 1, Colors.subtleAccentand background is 'white'
components/ListItemActor.js
Exercise 2
FontSizes.giganticColors.background
Container has: a background with color: Colors.highlight
components/MainHeader.js
Image is 40x90
FontSizes.subheadWith weight ‘200’Colors.background
Pro exercise: Think how would you add support for themes
Dimensions
import { Dimensions,} from 'react-native'
const windowSize = Dimensions.get('window')
mainImage: { height: windowSize.height /3, width: undefined},
components/MovieHeader.js
Dimensions
import { Dimensions,} from 'react-native'
const windowSize = Dimensions.get('window')
mainImage: { height: windowSize.height /3, width: undefined},
Our image height depends on the Height of the window
Use sparingly
components/MovieHeader.js
Dimensions
import { Dimensions,} from 'react-native'
const windowSize = Dimensions.get('window')
mainImage: { height: windowSize.height /3, width: undefined},
Our image height depends on the Height of the window
Use sparingly
Exercise: Can you make another style dependant of Dimensions? What will happen if the device is rotated? Can you find anything in the documentation to fix it?
components/MovieHeader.js
Further reading
https://www.okgrow.com/posts/react-native-styling-tips
https://madebymany.com/stories/a-year-of-react-native-styling-part-1
https://medium.com/robin-powered/introducing-glamorous-for-react-native-1b8365e7f33f
https://github.com/styled-components/styled-components
Explore libraries to do CSS in JS
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column' flexDirection: ‘row’(Default)
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column' flexDirection: ‘row’(Default)
main direction
cros
s dire
ctio
n
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column' flexDirection: ‘row’(Default)
main direction
cros
s dire
ctio
n
cross direction
mai
n di
rect
ion
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column’
(Default)
‘flex-start’ ‘flex-end’ ‘center' ‘space-around’ ‘space-between’
flexDirection: ‘row’
(Default)
‘flex-start’ ‘flex-end’ ‘center' ‘space-around’ ‘space-between’
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column’
(Default)
‘flex-start’ ‘flex-end’ ‘center' ‘stretch’ ‘baseline’
flexDirection: ‘row’
(Default)
‘flex-start’ ‘flex-end’ ‘center' ‘stretch’ ‘baseline’
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘row’
‘baseline’
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flexDirection: ‘column’
alignSelf: ’end’
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flex: 1
flex: 0flex: 0
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flex: 5
flex: 2
flex: 3
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flex: 0.5
flex: 0.2
flex: 0.3
This is flexbox realmflexDirection justifyContent alignItems alignSelf flex alignContent flexBasis flexGrow flexShrink flexWrap
flex: 25
flex: 10
flex: 15
Exercise 2
Hint: create subviews if you need them
Optional: can you come up with a different layout for any of our three components?
app/components/MainHeader.js
Further reading
https://facebook.github.io/yoga/docs/getting-started/Docs:
https://github.com/jondot/ReactNativeKatasVery good practice:
Naive lists, as in the web
export default class Movie extends Component { constructor(props) { super(props) this.state = { movie: movies.find((movie) => movie.name === 'Pulp Fiction') } }
render() { return ( <View> <MovieHeader movie={this.state.movie}/> { this.state.movie.actors.map(actor => ( <ListItem key={actor} name={actor} image={actors[actor].image}/> ))} </View> ) }}
app/components/Movie.js
Naive lists, as in the web
export default class Movie extends Component { constructor(props) { super(props) this.state = { movie: movies.find((movie) => movie.name === 'Pulp Fiction') } }
render() { return ( <View> <MovieHeader movie={this.state.movie}/> { this.state.movie.actors.map(actor => ( <ListItem key={actor} name={actor} image={actors[actor].image}/> ))} </View> ) }}
Important to help the reconciler do its work
app/components/Movie.js
Exercise
git checkout lists
Can you build a list of movies in app/components/MovieList.js ?
(To discard your changes)git reset HEAD --hard
FlatList
Highly optimized List component
Features:
• Scroll loading (onEndReached).
• Pull to refresh (onRefresh / refreshing).
• Configurable viewability (VPV) callbacks (onViewableItemsChanged / viewabilityConfig).
• Horizontal mode (horizontal).
• Intelligent item and section separators.
• Multi-column support (numColumns)
• scrollToEnd, scrollToIndex, and scrollToItem
• Better Flow typing.
FlatList
render() { return ( <View> <MovieHeader movie={this.state.movie}/> <FlatList data={this.state.movie.actors} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> } /> </View> )}
app/components/Movie.js
FlatList
What about the keys?
<FlatList data={this.state.movie.actors} keyExtractor={item => item} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> }/>
FlatList
What about the keys?
<FlatList data={this.state.movie.actors} keyExtractor={item => item} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> }/>
FlatList
Scrolleable area
<FlatList data={this.state.movie.actors} keyExtractor={item => item} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> }/>
<MovieHeader movie={this.state.movie}/>
FlatList
Desired scrolleable area
<FlatList data={this.state.movie.actors} ListHeaderComponent={<MovieHeader movie={this.state.movie}/>} keyExtractor={item => item} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> }/>
FlatList
Desired scrolleable area
<FlatList data={this.state.movie.actors} ListHeaderComponent={<MovieHeader movie={this.state.movie}/>} keyExtractor={item => item} renderItem={({item}) => <ListItem name={item} image={this.state.actors[item].image}/> }/>
Exercise
Can you use FlatList in app/components/MovieList.js ?
git checkout flatLists
item => itemreminder
In this case works asfunction(item) { return item}
git reset HEAD —hard(To discard your changes)
Further reading
https://facebook.github.io/react-native/blog/2017/03/13/better-list-views.html
Read the docs of the components:
FlatList SectionList VirtualizedList
Let’s do it
const App = StackNavigator({ Home: { screen: MovieList }, Movie: { screen: Movie },}, { navigationOptions: { headerTintColor: Colors.accent, headerStyle: Styles.header, }})
app/App.js
Let’s do it
const App = StackNavigator({ Home: { screen: MovieList }, Movie: { screen: Movie },}, { navigationOptions: { headerTintColor: Colors.accent, headerStyle: Styles.header, }})
app/App.jsexport default class MovieList extends Component { static navigationOptions = { title: 'Movies', } //…
app/components/MovieList.js
Let’s do it
const App = StackNavigator({ Home: { screen: MovieList }, Movie: { screen: Movie },}, { navigationOptions: { headerTintColor: Colors.accent, headerStyle: Styles.header, }})
app/App.jsexport default class MovieList extends Component { static navigationOptions = { title: 'Movies', } //…
app/components/MovieList.js
<FlatList data={this.state.movies} ListHeaderComponent={<MainHeader/>} keyExtractor={item => item.name} renderItem={({item}) => <TouchableHighlight underlayColor={Colors.subtleAccent} activeOpacity={0.5} onPress={() => navigate('Movie', {name: item.name})} > <View> <ListItem name={item.name} image={item.image}/> </View> </TouchableHighlight> }/>
In render()
Let’s do it
const App = StackNavigator({ Home: { screen: MovieList }, Movie: { screen: Movie },}, { navigationOptions: { headerTintColor: Colors.accent, headerStyle: Styles.header, }})
app/App.jsexport default class MovieList extends Component { static navigationOptions = { title: 'Movies', } //…
app/components/MovieList.js
<FlatList data={this.state.movies} ListHeaderComponent={<MainHeader/>} keyExtractor={item => item.name} renderItem={({item}) => <TouchableHighlight underlayColor={Colors.subtleAccent} activeOpacity={0.5} onPress={() => navigate('Movie', {name: item.name})} > <View> <ListItem name={item.name} image={item.image}/> </View> </TouchableHighlight> }/>
In render()
ExerciseCan you make a navigation transition from Movie to app/components/Actor ?
Steps: - Declare the screen in app/App.js - Use a TouchableHighlight to capture onPress in the actors list of <Movie/> - Provide an appropriate title in <Actor/> - Make the actor displayed based on props.navigation.state.params.name
Optional: have a look at https://reactnavigation.org/docs/navigators/stack#StackNavigatorConfigAnd tweak the navigation (Ideas: mode modal, add something to headerRight)
Let’s do it
componentDidMount() { return fetch(baseUrl + '/movies') .then((response) => response.json()) .then((responseJson) => { this.setState({ isLoading: false, movies: responseJson, }) }) .catch((error) => { console.error(error); })}
app/components/MovieList.js
Let’s do it
git checkout networking yarn start-server
(To discard your changes)
git reset HEAD --hard
Further reading
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Docs:
https://github.com/mzabriskie/axios
Additional libraries:
Cases where it is needed
Installing packages that have a native side Making our own changes or components Installing assets, such as fonts …
Let’s do it
"rnpm": { "assets": ["./assets/fonts/"] }
package.json
git checkout mod-native
(To discard your changes)
git reset HEAD --hard
Let’s do it
"rnpm": { "assets": ["./assets/fonts/"] }
package.json
react-native link
git checkout mod-native
(To discard your changes)
git reset HEAD --hard
Assets linked
Changes to be committed: (use "git reset HEAD <file>..." to unstage)
new file: android/app/src/main/assets/fonts/OleoScript-Bold.ttfnew file: android/app/src/main/assets/fonts/OleoScript-Regular.ttfmodified: ios/travolta.xcodeproj/project.pbxprojmodified: ios/travolta/Info.plistmodified: package.json
Summary:What is React Native Starting a project Working with Styles Layout Lists Navigation Networking Touching the native side
Thanks! @nacmartin [email protected]