community.infinite.red
#campminder-training
0.1 + 0.2 // 0.30000000000000004
1 - 2 + 3 * 4 / 5 % 6 // 1.4
parseInt('123', 10) // 123
parseInt('010', 10) // 10
parseInt('hello', 10) // NaN (i.e. Not a Number)
NaN + 5 // NaN
NaN === NaN // false
isNaN(NaN) // true
1 / 0 // Infinity
-1 / 0 // -Infinity
isFinite(Infinity) // false
"\u03BB" === "λ"
"\uD83D\uDC10" === "🐐"
"react".length // 5
"react".charAt(0) // "r"
"react".toUpperCase() // "REACT"
"hello, world".replace("world", "react") // "hello, react"
null !== undefined // true
Boolean(false) // false
Boolean(0) // false
Boolean("") // false
Boolean(NaN) // false
Boolean(null) // false
Boolean(undefined) // false
Similar set of operators and control structures to other languages in the C family
// logical operators
true && false || 0 // 0
// conditional statements
if (true && 1) {
// always executed
} else if(false || 0) {
// never executed
} else {
// also never
}
// ternary operator
true
? "an expression"
: "" // "an expression"
// while loops
while(true) { /* loop forever */ }
do {
/* execute once; loop never */
} while(false)
// for loops
for (let i = 0; i < 5; i++) {
// execute 5 times
}
for (let value of [1,2,3]) {
// do something with value
}
for (let property in { key: 'value' }) {
// do something with object property
}
// create using the new keyword
new Object()
// or literal
let obj = {
name: "Mappy",
role: "associates stuff"
}
// access with brackets
obj["name"] // "Mappy"
// or dot notation
obj.role // "associates stuff"
// a prototype
function Person(name, age) {
this.name = name;
this.age = age;
}
// an instance
const frank = new Person("Frank", 38)
// ES6 adds the following sugar
class Frank extends Person {
constructor(props) {
super(props)
}
}
// create with new
const a = new Array()
// or literal syntax
const snacks = ["tacos","nachos","cheetos"]
// iterate with for loop
for(const snack of snacks) {
eat(snack)
}
// or with an iterator method
snacks.map(function(snack) {
return snack.toUpperCase()
})
New variable types
let
const
var
NEVER
Sometimes
Always
// var declaration
function varTest() {
var x = 1
if (true) {
var x = 2 // same variable!
console.log(x) // 2
}
console.log(x) // 2
}
New variable types
// let declaration
function letTest() {
let x = 1
if (true) {
let x = 2 // different variable
console.log(x) // 2
}
console.log(x) // 1
}
var
let
const key = "mykey"
key = "newkey"
// error "key" is read only
New variable types -
const
const person = {
name: "Jennifer",
age: 43,
occupation: "Dentist",
}
person.name = "Jim"
New variable types -
const
{
"age": 43,
"name": "Jim",
"occupation": "Dentist"
}
➡
Arrow functions
ES5
ES6
var sayName =
function() {}
const sayName =
() => {}
() => {}
this
bound to global
const getFullName = (first, last) => {
return first + " " + last
}
Functions - implicit vs explicit return
var getFullName = function(first, last) {
return first + " " + last
}
ES5
ES6
const getFullName = (first, last) => first + " " + last
const getFullName = (first, last) =>
first + " " + last
explicit
implicit
explicit
ES6
const sayName = (name) => console.log("I am " + name + " !")
Arrow functions
Parameters
const sayName = name => console.log("I am " + name + " !")
const addThree = (a, b, c) => a + b + c
const abc = ["a", "b", "c"]
const def = ["d", "e", "f"]
const alpha = [ ...abc, ...def ]
["a", "b", "c", "d", "e", "f"]
Spread operator
Spread array
const basics = {firstName: "Frank", lastName: "von Hoven"}
const attributes = {job: "Software Engineer"}
const person = {...basics, ...attributes, eyes: "brown"}
{
firstName: "Frank",
lastName: "von Hoven",
job: "Software Engineer",
eyes: "brown"
}
Spread object
...
const name = person.name
const height = person.height
const location = person.location
console.log(name, height, location)
Object { destructuring }
ES5
const {
name,
height,
location,
sports
} = person
console.log(name, height, location)
ES6
const person = {
name: "Chris",
hairColor: "brown",
height: "6'1",
location: "Boulder",
sports: ["football", "tennis"]
}
// "Chris", "6'1", "Boulder"
const lettuce = toppings[0]
const pickles = toppings[1]
console.log(lettuce, pickles)
Array [ destructuring ]
ES5
const [lettuce, pickles] = toppings
// destructure toppings by index
console.log(lettuce, pickles)
ES6
const toppings = [
"lettuce",
"pickles",
"tomatoes",
"onions"
]
// "lettuce", "pickles"
https://github.com/lukehoban/es6features
This:
Compiles to:
<p style={{ color: "blue" }}>
Click Me
</p>
React.createElement(
"p",
{style: { color: "blue"}},
"Click Me"
)
const MyComponent = <p>Hello World</p>
const MyImage = <img src={someSource} style={styleObj} />
<MyComponent/>
<MyImage/>
Use in JSX like this:
const person = { name: "Chris", age: 22 }
const MyComponent = <p>Hello { person.name }</p>
const person = { name: "Chris", age: 22 }
const MyComponent = <p>Hello { getName() }</p>
const getName = () => person.name
renderLegalPerson = () => {
const person = { name: "Chris", age: 22 }
if (person.age >= 20) {
return <p>{person.name}</p>
} else {
return <p>Age is below 20</p>
}
}
...
<div>
{ this.renderLegalPerson() }
</div>
...
const person = { name: "Chris", age: 22 }
<p>{person.name} { person.age > 20 ? "Is over 20" : "Is not over 20" }</p>
ternary operator
tl;dr
class MyComponent extends React.Component {
render() {
return (
<p>Hello World</p>
)
}
}
Class
const MyComponent = () => (
<p>Hello World</p>
)
<MyComponent />
Function
vs
Components ➡ React elements - what should appear on the screen.
Styles can be created one of three ways:
inline styles
<p style={{color: "red"}}>Hello World</p>
<div style={{width: 300}}/>
style object
const styles = {
text: {
color: "red"
}
}
<p style={styles.text}>Hello World</p>
...
const styles = {
text: {
color: 'red'
}
}
<p style={[styles.text, { fontSize: 32 } ]}>Hello World</p>
Combining inline styles with style object
with an array of styles
Dynamic styling
state = {
warning: true
}
...
render() {
const fontColor = this.state.warning ? 'red' : 'black'
return (
<div>
<p style={{color: fontColor}}>Hello World</p>
</div>
)
}
backgroundColor
background-color
vs
CSS
import "./styles.css"
...
<div className="container">
<p className="funText">Hello World</p>
</div>
...
// in styles.css
.container {
text-align: center;
}
.funText {
color: fuchsia;
font-size: 100px;
}
code
import React from "react"
class App extends React.Component {
state = { name: "Chris" }
// lifecycle methods
render() {
return (
<p>{this.state.name}</p>
)
}
}
class
<App />
import React from "react"
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
name: "Chris"
}
}
render() {
return(
<p>{this.state.name}</p>
)
}
}
Creating state
Using constructor to declare state
import React from "react"
class App extends React.Component {
state = { name: "Chris" }
updateName = () => {
this.setState({ name: "Amanda" })
}
render() {
return(
<div>
<p onClick={this.updateName}>
{this.state.name}
</p>
</div>
)
}
}
Updating state with
setState
Frequently Used React Lifecycle methods
code
const [count, setCount] = useState(0)
function useState(initialValue) {
let _val = initialValue // _val is a local variable created by useState
function state() { // state is an inner function, a closure
return _val
}
function setState(newVal) { // setState is also a closure
_val = newVal
}
return [state, setState] // exposing functions for external use
}
const [foo, setFoo] = useState(0) // using array destructuring
console.log(foo()) // 0 - the initialValue we gave
setFoo(1) // sets _val inside useState's scope
console.log(foo()) // 1 - new initialValue, despite exact same call
const MyReact = (function() {
let hooks = [],
currentHook = 0 // array of hooks, and an iterator!
return {
render(Component) {
const Comp = Component() // run effects
Comp.render()
currentHook = 0 // reset for next render
return Comp
},
useState(initialValue) {
hooks[currentHook] = hooks[currentHook] || initialValue
const setStateHookIndex = currentHook // for setState's closure!
const setState = newState => (hooks[setStateHookIndex] = newState)
return [hooks[currentHook++], setState]
}
}
})() // MyReact is an IIFE (moar closures!!!)
code
[1, 2, 3]
Array →
[1, 2, 3].map()
.map() →
[1, 2, 3].map((item) => item)
.map() →
[1, 2, 3].map((item, index) => item + index)
.map() →
[1, 2, 3]
returns →
[1, 3, 5]
returns →
const items = [{name: "Nick"}, {name: "Bill"}, {name: "Steve"}]
items.map((item) => ?)
Bill
Nick
Steve
items.map((item) => <p>{item.name}</p>)
code
export default App // currently exporting App
// 1) create new "Screen"
const CampDetailsScreen = () => {
return (
// Your code Here
)
}
// 2) export default the new screen - "CampDetailsScreen"
export default CampDetailsScreen // in App.js you should have this now
Build this on your own 👍🤞
react-navigation
npm i @react-navigation/web --save
Step 1: Install react-navigation
npm i @react-navigation/core --save
createSwitchNavigator
Step 2: import createSwitchNavigator
// App.js
import { createSwitchNavigator } from "@react-navigation/core"
createBrowserApp
Step 3: import createBrowserApp
// App.js
import { createBrowserApp } from "@react-navigation/web"
Step 4: Create navigation screens using components
import { HomeScreen } from "./screens/HomeScreen"
import { InfoScreen } from "./screens/InfoScreen"
...
const MyHomeRoutes = createSwitchNavigator(
{
Home: HomeScreen, // routes
Info: InfoScreen
},
{ initialRouteName: "Info" } // configuration
)
createSwitchNavigator takes 2 arguments:
Step 5: Render Navigation
// in App.js
...
const AppNavigator = createSwitchNavigator({
camps: CampListScreen,
camp: CampDetailsScreen,
})
const App = createBrowserApp(AppNavigator)
export default App
code
<Tile/> - CampListScreen
<Header/> - App-wide
<Footer/> - App-wide
code
Main methods:
setItem
clear
getItem
removeItem
Main methods:
setItem("key", "value")
clear()
getItem("key")
removeItem("key")
code
Overview
Opinionated - How data should be structured and updated
Typed — Includes its own typed API
Models — You build trees of models
Common typings of types:
Uses Observers
Observers allow:
Setup model (store)
import { types } from "mobx-state-tree"
const RootStore = types.model({
userId: types.string
})
...
Add some actions
import { types } from "mobx-state-tree"
const RootStore = types.model({
userId: types.string
})
.actions(self => ({
setUserId(id) {
self.userId = id
}
}))
...
Create the store!
import { types } from "mobx-state-tree"
const RootStore = types.model({
userId: types.string
})
.actions(self => ({
setUserId(id) {
self.userId = id
}
}))
export const store = RootStore.create()
const defaultValue = "so contextual"
// create the context
const MyContext = React.createContext(defaultValue)
// provide in a top level component
render() {
return (
<MyContext.Provider value={"so contextual"}>
{children}
</MyContext>
)
}
// use in a component
const context = useContext(MyContext)
context === "so contextual"
Test individual parts (e.g. functions, objects) to ensure they interface and work as expected
Test individual React components apart from where they are used in the application
Test that components have not changed by comparing snapshots of the React tree
Test your entire application the way a user would, simulating clicks and checking for components on the screen
code
View
ScrollView
Text
TextInput
Image
TouchableOpacity
React | React Native |
---|---|
<div> | <View> |
<p> | <Text> |
<input /> | <TextInput /> |
<button> | <TouchableOpacity /> |
Styles can be created one of three ways:
StyleSheet
import { StyleSheet, View, Text } from "react-native"
...
const styles = StyleSheet.create({
container: {
width: 300,
height: 130
},
text: {
color: "red"
}
})
...
<View style={styles.container}>
<Text style={styles.text}>Hello World</Text>
</View>
StyleSheet.create({...})
...
render() {
const data = [
{ key: "Chris" },
{ key: "Amanda" }
]
return (
<View>
<FlatList
data={data}
renderItem={({ item }) =>
<Text>{item.key}</Text>}
/>
</View>
)
}
Requires 2 props:
data
renderItem
[ ]
({item}) => { }
...
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
/>
</View>
)
}
keyExtractor
...
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
ItemSeparatorComponent={() => <View />}
/>
</View>
)
}
ItemSeparatorComponent
...
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
/>
</View>
)
}
onRefresh
code
react-navigation
The community solution to navigation is a standalone library that allows developers to set up the screens of an app with just a few lines of code
Main types of navigators:
StackNavigator
SwitchNavigator
TabNavigator
DrawerNavigator
npm i react-navigation --save
Step 1: Install react-navigation
yarn add react-navigation
or
npm i react-native-gesture-handler --save
Step 1a: Install react-native-gesture-handler
yarn add react-native-gesture-handler
or
Step 1b: Link react-native-gesture-handler
react-native link react-native-gesture-handler
createStackNavigator
Step 2: import createStackNavigator
import { createStackNavigator } from "react-navigation"
Step 3: import createAppContainer
import { createStackNavigator, createAppContainer } from "react-navigation"
createAppContainer
Step 4: Create navigation screens using components
const MyHomeRoutes = createStackNavigator({
Home: { screen: Home },
Info: { screen: Info }
},{
initialRouteName: "Home"
}
})
createStackNavigator takes 2 arguments:
StackNavigator - Basic Implementation
const Home = () => (
<Text>Hello from Home</Text>
)
const Info = () => (
<Text>Hello from Info</Text>
)
const AppStack = StackNavigator({
Home: { screen: Home },
Info: { screen: Info }
})
const App = createAppContainer(AppStack)
AppRegistry.registerComponent("App", () => App)
code
A component can specify the layout of its children using the flexbox algorithm. Flexbox is designed to provide a consistent layout on different screen sizes.
You will normally use a combination of:
flexDirection
alignItems
justifyContent
to achieve the right layout.
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
<View style={styles.container}>
<View style={styles.box1} />
</View>
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
box2: {
flex: 1,
backgroundColor: 'orange'
},
<View style={styles.container}>
<View style={styles.box1} />
<View style={styles.box2} />
</View>
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
box2: {
flex: 2, // "Change flex from 1 to 2"
backgroundColor: 'orange'
},
<View style={styles.container}>
<View style={styles.box1} />
<View style={styles.box2} />
</View>
flexDirection
container: {
flex: 1
}
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
- column
flexDirection
container: {
flex: 1,
flexDirection: 'row'
}
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
- row
justifyContent
Determines the distribution of children along the primary axis.
flexDirection: column
flexDirection: row
⬆
⬇
⬅ ➡
justifyContent:
justifyContent:
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
'center'
container: {
flex: 1,
justifyContent: 'center'
}
container: {
flex: 1,
justifyContent: 'flex-end'
}
container: {
flex: 1
}
'flex-end'
container: {
flex: 1,
justifyContent: "space-around"
}
'space-around'
container: {
flex: 1,
justifyContent: "space-between"
}
'space-between'
alignItems
Determines the distribution of children along the secondary axis.
flexDirection: column
⬆
⟷
⬇
⬅ ↕ ➡
alignItems: center
flexDirection: row
alignItems: center
Default - 'stretch'
horizontal axis
vertical axis
alignItems:
container: {
flex: 1,
alignItems: 'center'
}
'center'
in action
'flex-end'
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
container: {
flex: 1,
alignItems: 'flex-end'
}
exercise
code
createBottomTabNavigator
import createBottomTabNavigator
import { createBottomTabNavigator } from "react-navigation"
Create Tab routes using screens or other navigators
const Tabs = createBottomTabNavigator(
{
Home: HomeScreen,
Input: InputScreen
},
{
initialRouteName: "Home",
tabBarOptions: {
activeBackgroundColor: "orange",
inactiveBackgroundColor: "yellow"
}
}
)
createBottomTabNavigator can also take 2 arguments:
code
npm i mobx mobx-react mobx-state-tree --save
npm i mobx mobx-react mobx-state-tree --save
Pass along data/actions from a named store
inject
inject("rootStore")
Make the screen pay attention to the store
observer
inject("rootStore")(observer(YourScreen))
code
Useful props:
Main methods:
setItem
multiGet
getItem
multiSet
setItem(key: string, value: string, ?(error) => void)
setItem
getItem(key: string, ?(error, result: ?string) => void)
getItem
setItem("username", "FrankTheTank")
getItem("username", (error, result) => console.log(error, result))
multiSet(keyValuePairs: Array<Array<string>>, ?(errors) => void)
multiSet
multiSet(
[
["username", "FrankTheTank"],
["password", "password_snake_cased"]
],
(errors) => console.log(errors)
)
multiGet(keys: Array<string>, ?(errors, result: Array<Array<string>>) => void)
multiGet
multiGet(
["username", "password"],
(errors, result) => console.log(result)
)
// [
// ["username", "FrankTheTank"],
// ["password", "password_snake_cased"]
// ]
code