Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Learning MobX
import React, {Component} from 'react'
import { observable } from 'mobx'
import { observer } from 'mobx-react'
@observer
class Counter extends Component{
@observable count = 0
render (){
return(
<div >
Counter: {this.count} <br/>
<button onClick={this.handleDec}>-</button>
<button onClick={this.handleInc}>+</button>
</div>
)
}
handleDec = () => this.count--
handleInc = ()=> this.count++
}
export default <Counter/>
import React, {Component} from 'react'
import {observer} from 'mobx-react'
import {Provider, inject} from 'mobx-react'
const TimerDisplay = ({timer,text})=>(
<div style={display.displayContainer}>
<div style={display.time}>{text}</div>
<div style={display.lap}>{timer.display}</div>
</div>
)
const RunningButtons = inject('store')(observer(({store})=>(
<div>
<button style={{...button, color: '#fd3d2a'}} onClick={() => store.stopTimer()}>
stop
</button>
<button style={button} onClick={() => store.lapTimer()}>
lap
</button>
</div>
)))
const StartButtons = inject('store')(observer(({store})=>(
<div>
<button style={{...button, color: '#4bd761'}} onClick={() => store.startTimer()}>
start
</button>
<button style={button} onClick={() => store.resetTimer()}>
reset
</button>
</div>
)))
export default observer( ({store})=>{
const {mainDisplay, isRunning, lapData} = store
return (
<Provider store={store}>
<div>
<div style={main}>
{mainDisplay}
</div>
<div>
<div style={bContainer}>
{isRunning ? <RunningButtons />:<StartButtons />}
</div>
<div>
{lapData.map( ({timer, text},i) => <TimerDisplay key={i} timer={timer} text={text}/>)}
</div>
</div>
</div>
</Provider>
)
})
const display ={
displayContainer:{
display: 'flex',
borderBottom: '1px solid #d9dae0',
fontSize: 30
},
time :{
fontSize: 30,
fontFamily: 'HelveticaNeue-UltraLight',
color: '#7f8083',
padding: 20,
flex: 1
},
lap:{
padding: 20,
fontFamily: 'HelveticaNeue-UltraLight',
color: '#7f8083',
}
}
const button ={
fontFamily: 'HelveticaNeue-UltraLight',
fontSize: 20,
width: 72,
height: 72,
margin: 24,
padding: 0,
cursor: 'pointer',
letterSpacing: 1,
border: 0,
borderRadius: '50%',
outline: 'none',
background: 'white',
}
const main = {
background: 'white',
height: 120,
fontSize: 60,
fontFamily: 'HelveticaNeue-UltraLight',
border: 'solid #cecfd0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
const bContainer={
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
const moment = require('moment'),
{observable, computed, action, runInAction} = require('mobx'),
format = require('format-number-with-string')
class Timer{
@observable milliseconds = 0
@observable savedMilliseconds =0
constructor(initialMilliseconds=0){
runInAction('Set observed state values',
()=> this.milliseconds= initialMilliseconds)
}
@computed get totalMilliSeconds(){
return this.milliseconds + this.savedMilliseconds
}
@computed get display(){
const tenMilliSeconds = parseInt(this.totalMilliSeconds/10, 10)
const seconds = parseInt(tenMilliSeconds/100, 0)
const minutes = parseInt(seconds / 60, 10)
return `${minutes} : ${format(seconds % 60, '00')} : ${format(tenMilliSeconds % 100, '00')}`;
}
@action saveTime(){
this.savedMilliseconds += this.milliseconds
this.milliseconds=0
}
@action reset(){
return this.savedMilliseconds = 0
}
}
export default class {
@observable isRunning = false
@observable timer = new Timer()
@observable startTime
@observable laps =[]
@computed get mainDisplay(){
return this.timer.display
}
@computed get lapTime() {
return this.laps.map( timer => timer.totalMilliSeconds)
.reduce((x, y) => x + y, 0);
}
// I dont understand this....
@action lapTimer() {
this.laps.push(new Timer(this.timer.totalMilliSeconds - this.lapTime));
}
@computed get lapData() {
return this.laps
.map( (timer, i) =>({timer, text: `Lap ${i + 1}`})).reverse()
}
@action stopTimer(){
this.timer.saveTime()
this.isRunning = false
}
@action measure(){
if (!this.isRunning) return;
this.timer.milliseconds = moment().diff(this.startTime);
setTimeout(() => this.measure(), 10);
}
@action startTimer(){
if (this.isRunning) return;
this.isRunning = true;
this.startTime = moment();
this.measure();
}
@action resetTimer(){
this.timer.reset()
this.laps = []
this.isRunning=false
}
}
import React, {Component} from 'react'
import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import { observable, computed, action } from 'mobx'
import { observer } from 'mobx-react'
import DevTools from 'mobx-react-devtools'
class Temperature {
id = Math.random()
@observable unit = "C"
@observable tempCelsius = 25
@computed get tempKelvin(){
console.log(`comping K`)
return this.tempCelsius + 273.15
}
@computed get tempFahrenheit(){
console.log(`comping F`)
return this.tempCelsius*(9/5)+32
}
@computed get temperature(){
console.log('comping temp')
switch(this.unit){
case "K": return `${this.tempKelvin} °K`
case "C": return `${this.tempCelsius} °C`
case "F": return `${this.tempFahrenheit} °F`
}
}
@action setUnit(newUnit){
this.unit = newUnit
}
@action setCelsius(deg){
this.tempCelsius = deg
}
@action('update temp and unit')
setTempandUnit(deg, unit){
this.setCelsius(deg)
this.setUnit(unit)
}
}
const temps = observable([])
temps.push(new Temperature())
const App = observer(
({temperatures}) => (
<div>
{temperatures.map( (t,i)=><div key={i}>{t.temperature}</div> )}
<br/>
</div>
)
)
render(
<AppContainer>
<App temperatures={temps} />
</AppContainer>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./App', () => {
const NextApp = require('./App').default;
render(
<AppContainer>
<NextApp temps={temps} />
</AppContainer>,
document.getElementById('root')
);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment