Skip to content

Commit

Permalink
Merge pull request #24 from dailydrip/redux-loop
Browse files Browse the repository at this point in the history
Add redux-loop
  • Loading branch information
knewter committed Jan 16, 2017
2 parents 1096437 + 3528d9d commit 6fcaf88
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 68 deletions.
8 changes: 4 additions & 4 deletions index.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import AppViewContainer from './src/modules/AppViewContainer'
class DailyDrip extends Component {
componentWillMount() {
// Load existing store state from async storage
console.log('loading storage')
storageLoader(store)
.then((newState) => console.log('Loaded state:', newState))
.catch((e) => console.log('Failed to load previous state', e))
// console.log('loading storage')
// storageLoader(store)
// .then((newState) => console.log('Loaded state:', newState))
// .catch((e) => console.log('Failed to load previous state', e))
}

render() {
Expand Down
33 changes: 28 additions & 5 deletions src/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,56 @@
export const FETCH_TOPICS = 'FETCH_TOPICS'
export const FETCH_DRIPS = 'FETCH_DRIPS'
export const SET_TOPICS = 'SET_TOPICS'
export const SET_DRIPS = 'SET_DRIPS'
export const SELECT_TOPIC = 'SELECT_TOPIC'
export const NO_OP = 'NO_OP'

const setTopics = (topics) => {
return {
type: FETCH_TOPICS,
type: SET_TOPICS,
topics,
}
}

const setDrips = (topicId, drips) => {
return {
type: FETCH_DRIPS,
type: SET_DRIPS,
topicId,
drips,
}
}

const fetchTopics = () => {
return {
type: FETCH_TOPICS
}
}

const fetchDrips = (topicId) => {
return {
type: FETCH_DRIPS,
topicId
}
}


const selectTopic = (topicId) => {
return {
type: SELECT_TOPIC,
topicId,
}
}

const Actions = {
const noOp = () => {
return {
type: NO_OP
}
}

export const Actions = {
setTopics,
setDrips,
selectTopic,
fetchTopics,
fetchDrips
}

export default Actions
2 changes: 1 addition & 1 deletion src/components/Drawer/DrawerContainer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { connect } from 'react-redux'
import Actions from '../../actions'
import { Actions } from '../../actions'
import Drawer from '../Drawer'

const mapStateToProps = (state) => {
Expand Down
3 changes: 2 additions & 1 deletion src/modules/AppView.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ class App extends Component {
}

checkAuth(navigate) {
let { fetchTopics } = this.props
AsyncStorage.getItem('auth_token').then((value) => {
if (value) {
this.props.fetchTopics()
fetchTopics()
} else {
if (navigate) {
navigate.to('login')
Expand Down
13 changes: 3 additions & 10 deletions src/modules/AppViewContainer.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { connect } from 'react-redux'
import AppView from './AppView'
import Immutable from 'immutable'
import Actions from '../actions'
import { Actions } from '../actions'
import API from '../api'

export default connect(
() => { return {} },
dispatch => {
return {
fetchTopics: () => {
API.getTopics().then((response) => {
const topicsMap = response.data.topics.reduce((acc, topic) => {
return acc.set(topic.id, Immutable.fromJS(topic))
}, Immutable.Map())
dispatch(Actions.setTopics(topicsMap))
}).catch((error) => {
console.log(error)
})
},
dispatch(Actions.fetchTopics())
}
}
}
)(AppView)
2 changes: 1 addition & 1 deletion src/scenes/Login/LoginContainer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Login from './index'
import { connect } from 'react-redux'
import API from '../../api'
import Actions from '../../actions'
import { Actions } from '../../actions'

const mapStateToProps = () => {
return {}
Expand Down
12 changes: 2 additions & 10 deletions src/scenes/Topic/TopicContainer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Topic from './index'
import { connect } from 'react-redux'
import API from '../../api'
import Actions from '../../actions'
import { Actions } from '../../actions'
import Immutable from 'immutable'

const mapStateToProps = (state) => {
Expand All @@ -17,14 +16,7 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => {
return {
fetchDrips: (topicId) => {
API.getDrips(topicId).then((response) => {
const dripsMap = response.data.drips.reduce((acc, drip) => {
return acc.set(drip.id, Immutable.fromJS(drip))
}, Immutable.Map())
dispatch(Actions.setDrips(topicId, dripsMap))
}).catch((error) => {
console.log(error)
})
dispatch(Actions.fetchDrips(topicId))
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/scenes/Topics/TopicsContainer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { connect } from 'react-redux'
import Topics from './index'
import Actions from '../../actions'
import { Actions } from '../../actions'

const mapStateToProps = (state) => {
const topics = state.get('topics')
Expand Down
38 changes: 25 additions & 13 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStore, applyMiddleware, compose } from 'redux'
import { combineReducers } from 'redux-immutablejs'
//import { combineReducers } from 'redux-immutablejs'
import * as storage from 'redux-storage'
import createEngine from 'redux-storage-engine-reactnativeasyncstorage'
import merger from 'redux-storage-merger-immutablejs'
Expand All @@ -19,32 +19,44 @@ import Immutable from 'immutable'
import * as reducers from './reducers'

// LOG OUT STATE CHANGES
// import createLogger from 'redux-logger'
// const loggerMiddleware = createLogger({
// stateTransformer: state => state && state.toJS(),
// })
import createLogger from 'redux-logger'
const loggerMiddleware = createLogger({
stateTransformer: state => state && state.toJS(),
})
// END LOG OUT STATE CHANGES

// STORE REDUX STATE
const reducer = storage.reducer(combineReducers(reducers), merger)
const storageEngine = createEngine('@DAILYDRIP.reduxStore')
const storageMiddleware = storage.createMiddleware(storageEngine)
export const storageLoader = storage.createLoader(storageEngine)
// const reducer = storage.reducer(combineReducers(reducers), merger)
// const storageEngine = createEngine('@DAILYDRIP.reduxStore')
// const storageMiddleware = storage.createMiddleware(storageEngine)
// export const storageLoader = storage.createLoader(storageEngine)
// END STORE REDUX STATE

const initialState = Immutable.fromJS({
topics: {},
selectedTopic: {}, // NOTE: This is presently intended to end up as just a map with a basic `id` key - this is because you can't do immutable ints and I wanted to use createReducer throughout, but it's probably dumb...
})

console.log('initialState', initialState)

const enhancer = compose(
// applyMiddleware(loggerMiddleware, storageMiddleware),
applyMiddleware(storageMiddleware),
//applyMiddleware(loggerMiddleware, storageMiddleware),
applyMiddleware(loggerMiddleware),
Loop.install(),
devTools()
devTools(),
)

const store = createStore(
Loop.combineReducers(
reducers,
Immutable.Map(),
(state, key) => state.get(key),
(state, key, value) => state.set(key, value)
),
initialState,
enhancer
)

const store = createStore(reducer, initialState, enhancer)
devTools.updateStore(store)

export default store
107 changes: 85 additions & 22 deletions src/store/reducers/topics.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,87 @@
import { createReducer } from 'redux-immutablejs'
import Immutable from 'immutable'
import { FETCH_TOPICS, FETCH_DRIPS } from '../../actions'

export default createReducer(Immutable.Map(), {
[FETCH_TOPICS]: (state, action) => {
return action.topics.map((topic) => {
// Look in the store and pull in any drips we already know about, since
// we don't have them here but we'd like to keep them for faster startup
// from storage
const existingTopic = state.get(topic.get('id').toString())
let newTopic
if (existingTopic) {
newTopic = topic.set('drips', existingTopic.get('drips'))
} else {
newTopic = topic
}
return newTopic
import { Actions, SET_TOPICS, SET_DRIPS, FETCH_TOPICS, FETCH_DRIPS } from '../../actions'
import { loop, Effects } from 'redux-loop';
import API from '../../api'


let fetchTopics = () => (
API.getTopics()
.then((response) => {
return Actions.setTopics(
response.data.topics
.reduce((acc, topic) => {
return acc
.set(topic.id, Immutable.fromJS(topic))
}, Immutable.Map())
)
})
.catch((err) => {
console.error(err)
return Actions.noOp()
})
},
[FETCH_DRIPS]: (state, { topicId, drips }) => {
return state.setIn([topicId, 'drips'], drips)
},
})
)

let fetchDrips = (topicId) => {
return API.getDrips(topicId)
.then((response) => {
return Actions.setDrips(
topicId,
response.data.drips
.reduce((acc, drip) => (
acc.set(drip.id, Immutable.fromJS(drip))
), Immutable.Map())
)})
.catch((err) => {
console.error(err)
return Actions.noOp()
})
}

export default function(state, action){
switch (action.type) {
case FETCH_TOPICS:
return loop(
state,
Effects.promise(fetchTopics)
)

case SET_TOPICS:
const topics = action.topics.map((topic) => {
// Look in the store and pull in any drips we already know about, since
// we don't have them here but we'd like to keep them for faster startup
// from storage
const existingTopic = state.get(topic.get('id').toString())
let newTopic
if (existingTopic) {
newTopic = topic.set('drips', existingTopic.get('drips'))
} else {
newTopic = topic
}
return newTopic
})

return loop(
topics,
Effects.none()
)

case FETCH_DRIPS:
return loop(
state,
Effects.promise(fetchDrips, action.topicId)
)

case SET_DRIPS:
return loop(
state
.setIn([action.topicId, 'drips'], action.drips),
Effects.none()
)

default:
return loop(
state,
Effects.none()
)
}
}

0 comments on commit 6fcaf88

Please sign in to comment.