export class Timeline extends Component {
componentWillMount () {
this.props.fetchTimeline()
}
render () {
const { f, photos, fetchTimeline } = this.props
return (
<BoardView
photos{photos.data}
fetchStatus={photos.fetchStatus}
hasMore={photos.hasMore}
onFetchMore={() => fetchTimeline(photos.entries.length)}
/>
)
}
}
const mapStateToProps = (state, ownProps) => ({
photos: getTimelinePhotos(state)
})
export const mapDispatchToProps = (dispatch, ownProps) => ({
fetchTimeline: (skip) => dispatch(fetchTimeline(skip))
})
export default translate()(connect(
mapStateToProps,
mapDispatchToProps
)(Timeline))
Avec pour les action creators :
import { getCollection, fetchCollection } from 'redux-cozy-api'
export const getTimelinePhotos = (state) => getCollection('timeline')
export const fetchTimeline = (skip) => fetchCollection('timeline', 'io.cozy.files', {
fields: ['dir_id', 'name', 'size', 'updated_at', 'metadata'],
selector: {
class: 'image',
trashed: false
},
sort: {
'metadata.datetime': 'desc'
},
skip
})
On pourrait améliorer un chouïa ainsi (le fetchMore est fourni par le selector de collections) :
export class Timeline extends Component {
componentWillMount () {
this.props.fetchTimeline()
}
render () {
const { f, photos, fetchTimeline } = this.props
return (
<BoardView
photos{photos.data}
fetchStatus={photos.fetchStatus}
hasMore={photos.hasMore}
onFetchMore={photos.fetchMore}
/>
)
}
}
const mapStateToProps = (state, ownProps) => ({
photos: getTimelinePhotos(state)
})
export const mapDispatchToProps = (dispatch, ownProps) => ({
fetchTimeline: () => dispatch(fetchTimeline())
})
export default translate()(connect(
mapStateToProps,
mapDispatchToProps
)(Timeline))
- on est habitué à cette structure là
- fetch et "sélection" du state décorrélés
- besoin d'une instance globale d'un "client" pour gérer plus facilement certaines choses (schemas, indexes...)
const Timeline = ({ photos }) => (
<BoardView
photos{photos.data}
fetchStatus={photos.fetchStatus}
hasMore={photos.hasMore}
onFetchMore={photos.fetchMore}
/>
)
const TimelinePhotos = (ownProps) => ({
photos: {
type: 'io.cozy.files',
selector: {
class: 'image',
trashed: false
},
sort: {
'metadata.datetime': 'desc'
}
}
})
export default cozyConnect(TimelinePhotos)(Timeline)
- parait nettement plus clean
- facile d'avoir une instance client, qui en plus reste cachée
- comment gérer les "mutations" ?
- signifie un gros travail sur le HOC car on n'utiliserait plus le
connect
dereact-redux
et toutes ses optims
export class Timeline extends Component {
componentWillMount () {
this.props.client.fetchCollection('timeline')
}
updatePhoto = (photo) => {
this.props.client.updateDocument(photo)
}
render () {
const { f, photos } = this.props
return (
<BoardView
photos{photos.data}
fetchStatus={photos.fetchStatus}
hasMore={photos.hasMore}
onFetchMore={photos.fetchMore}
onEdit={this.updatePhoto}
/>
)
}
}
const mapStateToProps = (state, ownProps) => ({
photos: getCollection(state, 'timeline')
})
export default cozyConnect(mapStateToProps)(Timeline)
cozyConnect
vient injecter t
, et surtout client
qui détient une ref au store et peut ainsi dispatcher directement des actions. Il wrappe de surcroit le composant avec un connect
classique.
- plutôt clean
- mutations faciles à gérer
- le client qui "fuit" dans les composants, mais est-ce si grave ?
- toujours une décorrélation entre le fetch et la sélection du state
Utiliser un middleware redux pour fournir aux action creators génériques de redux-cozy-api une instance de client. Il faut pour cela donner une forme spécifique à ces actions creators :
export const fetchCollection = (collectionName) => ({
type: FETCH_COLLECTION,
promise: (client) => client.fetchCollection(collectionName)
})
- le client n'apparait pas dans les composants
- toujours une décorrélation entre le fetch et la sélection du state
On utilise un middleware spécifique de type solution #2 et un HOC spécifique :
class Timeline extends Component {
render () {
const { photos, uploadPhoto } = this.props
return (
<BoardView
photoLists={photoLists}
fetchStatus={photos.fetchStatus}
hasMore={photos.hasMore}
photosContext='timeline'
onFetchMore={photos.fetchMore}
onUpload={uploadPhoto}
/>
)
}
}
export default cozyConnect('photos', () => fetchTimeline(), { uploadPhoto })(Timeline)
Avec :
import { fetchCollection, createFile } from '../../lib/redux-cozy-client'
export const fetchTimeline = (skip = 0) => fetchCollection(TIMELINE, FILES_DOCTYPE, {
fields: ['dir_id', 'name', 'size', 'updated_at', 'metadata'],
selector: {
class: 'image',
trashed: false
},
sort: {
'metadata.datetime': 'desc'
}
})
export const uploadPhoto = (photo) => createFile(photo, PHOTO_DIR)
On ne peut pas toujours se reposer sur les 5-6 action creators de la lib, certaines actions demanderont toujours un workflow complexe avec le client.
import { fetchCollection, makeActionCreator } from '../../lib/redux-cozy-client'
export const fetchTimeline = (skip = 0) => fetchCollection(TIMELINE, FILES_DOCTYPE, {
fields: ['dir_id', 'name', 'size', 'updated_at', 'metadata'],
selector: {
class: 'image',
trashed: false
},
sort: {
'metadata.datetime': 'desc'
}
})
export const uploadPhoto = (photo, dirName) => makeActionCreator(async client => {
const dir = await client.getOrCreateDirectory(dirName)
return createFile(photo, PHOTO_DIR) // must return a generic action
})