I’m hoping to start a discussion about the best design pattern for using React with Meteor. I’m about to start a new project and I have to decide between using mixins, decorators, or composable components.
I would vote for ClojureScript approach After playing with reagent for a while, it seems as best system. Kinda Immutable structures for the win.
From speed etc point of view, but the view and data separation question I am not sure
Other than that it would be separating data manipulation to reducers from your list.
I think using a higher order function like yours is ideal, but if MDG wanted to re-use the mixin logic, using the inside the Meteor.ReactData (in the example) would be do-able.
I’m kind of on the fence with sideloading minimongo data and having flux/redux store that data. The pro with the latter is that all the data is in once place… unfortunately that means there’s two copies in memory. You can still use flux/redux for local state, replacing Session and reactive dicts.
At first the time-travel debugging drew me in but once I dug into it the concepts are really nice.
They’re based off functional programming where you’re never mutating state (just making a copy and mutating that). It gets rid of all the events and just uses simple functions. It borrows the Elm language concept of having 1 tree of state for the whole app. This makes it really nice for React because it breaks down the data flow into a simple mental model.
Here’s a quick overview of the lifecycle. You can even log out all dispatches when debugging!
// in the UI somewhere
store.dispatch( selectPlayer(this.props._id) );
// func creates a meta data object.. aka 'action' and returns it
//
function selectPlayer(playerId) {
let player = Players.findOne(playerId);
let playerName = player.name || "N/A";
return {
type: 'SELECT_PLAYER',
playerId: playerId,
playerName: playerName
};
}
// reducer function merges old state (copy) with new changes based on action meta data
//
Reducers.players = function todos(state = {}, action) {
switch (action.type) {
case 'SELECT_PLAYER':
let newState = merge(state, {
selectedId: action.playerId,
selectedPlayerName: action.playerName
});
return newState;
case 'REMOVE_PLAYER':
// .....
return newState;
case 'HIDE_PLAYER:
// .....
return newState;
}
};
// then the store can be consumed to get new data, note that the players reducer
// is merged with global app state. you can combine serveral reducers (like todos, musicPlayer)
// to separate domains of state but still have one tree like below
//
store.getState() >>> // result in console
{
players: {
type: 'PLAYER_SELECTED',
playerId: '3jdhdkjfd7d8f3',
playerName: 'Nikola Tesla',
},
todos: [
{_id: '1d2g3', text: 'Learn Redux'},
{_id: '3h2g7', text: 'Take over the world'}
],
forms: {
create: "How now brown c",
email: "sally@gmail.com"
},
musicPlayer: {
foo: 1,
bar: 2
}
}
// or hookup to a React view with react-redux higher order component
// gets data via `this.props`
//
let AppContainer = React.createClass({
render() {
return (<App {...this.props} />);
}
});
this.AppContainer = connect(mapStateToProps)(AppContainer);