I'm just trying to learn the basics of React and Flux, and the above code works and I can see it works nicely.
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import UI from './components/ui.js'
ReactDOM.render(<UI />, document.getElementById('ui'));
component/ui.js
import React, { Component } from 'react'
import Dispatcher from '../dispatcher/dispatcher'
import PlayerStore from '../stores/playerstore'
import PlayerActions from '../actions/playeractions'
import { ActionTypes } from '../constants/actions'
export default class UI extends Component {
constructor(props, context) {
super(props, context)
// keep contexts
this.onPlayerStoreChange = this.onPlayerStoreChange.bind(this)
this.state = {
health: PlayerStore.health
}
}
componentDidMount() {
// listen for events that are broadcasted by the stores
PlayerStore.on('change', this.onPlayerStoreChange)
}
componentWillUnmount() {
PlayerStore.off('change', this.onPlayerStoreChange)
}
onPlayerStoreChange() {
// request the new data needed via the stores' public getter methods
const health = PlayerStore.health
// then call its own setState() or forceUpdate() method
// causing its render() method and the render() method of all its descendants to run.
this.setState({
health
})
}
healPlayer() {
// the dispatcher exposes a method that allows us to trigger a dispatch to the stores,
// and to include a payload of data, which we call an action
PlayerActions.healPlayer();
}
render() {
return (
<div>
<h2>UI</h2>
<p>hello gamemakers</p>
<p>health: { this.state.health }</p>
<p onClick={ this.healPlayer }><u>add</u></p>
</div>
)
}
}
stores/playerstore.js
import { EventEmitter } from 'events'
import Dispatcher from '../dispatcher/dispatcher.js'
import { ActionTypes } from '../constants/actions'
const state = {
health: 100,
fatigue: 100
}
const stat = {
strength: 1, // affects rof and damage
agility: 1, // affects speed
endurance: 1 // affects rate of fatigue
}
class PlayerStore extends EventEmitter {
constructor() {
super()
// register this store with the dispatcher
this.dispatchToken = Dispatcher.register(this.onAction.bind(this))
}
onAction(payload) {
// provide hooks to each respective action
switch(payload.type) {
case ActionTypes.PLAYER_HEALED:
this.increaseHealth()
break
case ActionTypes.PLAYER_INJURED:
this.iHaveNoMadeThisBitYet()
break
}
}
get health() {
return state.health
}
increaseHealth() {
state.health += 6
// broadcast an event declaring that the state has changed
// so that whoever is listening to this store can update themself
this.emit('change')
}
}
module.exports = new PlayerStore();
dispatcher/dispatcher.js
const Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
actions/playeractions.js
import { ActionTypes } from '../constants/actions'
import Dispatcher from '../dispatcher/dispatcher'
export default {
healPlayer: function() {
Dispatcher.dispatch({
type: ActionTypes.PLAYER_HEALED
})
}
}
Here are my points:
- It feels weird to have my variables defined above my class and use public getters and so on to retrieve the values (instead of defining it on the constructor. Is there a benefit to this? It looks cleaner but it feels odd.
- Have I used
import
correctly? I want to share theDispatcher
across multiple files so I useimport
in those files. Will both of those files will contain the reference to the same dispatcher 'object'? - Why do you often see that people take their actions out of the component and into an actions file? Is it to share actions between components?
- Shouldn't I just bind the actions straight onto the elements? In the UI I bind
healPlayer
which triggers an action. Is it okay just to bind the action? - And following this, couldn't I also just dispatch the event through the
Dispatcher
inhealPlayer
instead of dispatching it in theactions/playeractions.js
file?