It’s unfortunate that React and Redux add a lot of new terms. The good news is that you don’t have to use them unless you want to. Blaze still works
However, I would at least recommend learning about them to level yourself up as a developer. The actual tech (Redux/React) isn’t that important but learning the ‘philosophy’ of how they solve problems will help you be a better developer. It just gives you more tools in your toolbox.
The egghead video linked above is great! There’s only a few mins on hooking it up to React, it will show you what it is and how/why it works.
If you boil it down, these both heavily use a style called functional programming. Using this style allows you to break down problems into small chunks. If you’ve heard about code being ‘easier to reason about’, this is what they mean. It’s just easier to see what’s going on with a ‘thing’ at any given time. Usually this means very little magic as well.
@SkinnyGeek, I’ve picked out all the terms I do not understand or know from your last post:
I’ll try to break them down by referring to some great resources that are quick to consume. For a deep dive I recommend the ebook linked in a few posts above.
side effects
This is a term that means calling a function that does some other action outside of the function. For example calling jQuery to hide an element in a function. It can get really confusing if you don’t expect it, like this:
function addTwo(a, b) {
$('some-el').hide();
return a + b;
}
Here this function is very bug prone because you woudn’t expect addTwo
to mutate the DOM, you just expect it to add two numbers. This also makes it hard to re-use or test. This brings us to the next one:
Pure functions
This is a function that doesn’t have side effects. The thing you want to strive for. You can’t always make them pure but if possible, all the things it needs are passed in as params and no side effects are made. If they’re pure it also means you can call them again and again and you will always get the same result. This is why Redux needs the ‘reducer’ function to be ‘pure’ for time travel… if it’s making db calls when re-winding in time it won’t work the same each time.
ajax calls
You def. want to learn about these in depth, so you understand what options you have. These most closely map to meteor methods without any built in authentication.
https://www.youtube.com/watch?v=fEYx8dQr_cQ
reducers
This is a function that redux uses to take the ‘old state’ and merge it a piece of the ‘new state’. The name comes from the reduce function (you’re not actually using Array.prototype.reduce as a reducer though). Here’s a great video on that (and other FP stuff) from a Spotify engineer whos great at teaching!
If you don’t read/watch anything else please watch this, it’s worth 9 mins of your time… I promise!
https://www.youtube.com/watch?v=Wl98eZpkp-c
https://www.youtube.com/watch?v=Wl98eZpkp-c
**action creator** and **action**
This is a silly term coined by Facebook. It’s just a regular function that creates an action which is another word for an object literal with a payload for flux to use.
In Redux an action is an object like this that tells that app something is happening like this:
{type: 'BUTTON_PRESSED', favColor: 'red', userId: 'u123'}
The type
attr is what the ‘reducer’ watches for and the rest is just metadata that it can use (i’ll get to the reducer later but it just saves the payload data to memory).
To pass it to the reducer we just call dispatch
and call it a day:
var user = Meteor.user();
dispatch({type: 'BUTTON_PRESSED', favColor: 'red', userId: user._id})
Now you could gather up all of that data in your UI, and if it was simple that wouldn’t be so bad. However,… if you can make your UI so ‘dumb’ that it just gathers a bit of data from the DOM and calls a function that would be great. Then you know what your UI is responsible for.
The easiest way to do that is to use a… you guessed it… function to process our data for us. We’ll use this one to create the same ‘action’ as above… notice it’s just returning that object at the end:
// returns {Object} to be passed to reducer
function setFavoriteColor(data) {
var user = Meteor.user();
return {
type: 'BUTTON_PRESSED',
userId: user._id,
favColor: data.color,
}
}
In real life it could parse a form and send all of the payload to the action creator to validate and save. Here we’re using a few fields so either way is ok. Now we just call this in the UI… easy and clean!
dispatch(setFavoriteColor({color: 'red'}))
store
The store is just a single place (in Redux) where all of the app state lives. You can put the app in any state you want by modifying this tree of data. The data tree is just a simple object literal with keys and values.
The most powerful concept is that when you want to change how your UI looks, you can modify the data tree and the UI will reactively update. At all times a ‘snapshot’ of how the app should look is right there in one place (as opposed to scattered about).
For example:
// entire state aka store
{
posts: [{desc: 'one'},{desc: 'two'}],
viewer: {name: 'Adam B', userId: 'u123'}
drawer: {
isOpen: false,
type: 'admin',
}
}
If we want to open the drawer on a mobile app we think a bit differently… it’s not, use jQuery to add this class and hide that… it’s ok I need to dispatch an action to toggle the drawer.isOpen
to true
and I know it will slide open. So on the menu button you have an event handler that dispatches a dispatch(toggleDrawer)
action, write a function to return an action:
function toggleDrawer() {
return {
type: 'TOGGLE_DRAWER',
}
}
The reducer will watch for that type and flip the boolean:
// note a 'reducer' slices off part of the main state tree
// not shown here, it's optional but keeps these smaller we're
// only using this part of the entire state shown above:
// {
// isOpen: boolean,
// type: 'admin' | 'user'
// }
function drawerReducer(oldState, action) {
switch (action.type) {
case 'TOGGLE_DRAWER':
// overwrite isOpen value
var newState = _.merge(oldState, {isOpen: false});
return newState;
default:
return oldState
}
}
ok so the actions package up the data and send it to the reducer, which merges the old state with the new state. With Redux this is important because if it’s the same object the UI won’t update. If it’s a copy (aka new object) then it knows it changed and will trigger a UI (if connect is using the new keys).
once you wrap your head around it, IMHO it’s much more simple thatn Meteor because everything is just a function that returns something. The only parts not show are the ‘merge reducers’ function that tie the total store state together and the UI part with connect. To give you a taste of connect, here’s an example of a ‘main pane’ using the tree above to slide it open with CSS:
var MainView = React.createClass({
render: function() {
var clName = (props.isOpen) ? 'slide-open' : 'slide-close';
return (
<div className={clName}>
<SomeView />
</div>
)
}
});
// watch a few keys on the main tree and pass in as 'props' to comp.
function mapStateToProps(state) {
return { isOpen: state.drawer.isOpen }
}
export default connect(mapStateToProps)(MainView)
So that seems like a really complex way to toggle a class but i’m trying to keep it simple for the example. Also you can render this UI from a bug report’s copy of the state tree, or render on the server and send the tree down on initial load, or even undo-redo… jQuery can’t do that.
> Tell me why we need yet another tech, Redux with React, inside of Meteor again?
At the end of the day certain tools make a job easier. I have a few apps with very complex UI and lots of ‘local’ state and with those two tools my apps are more bug free than ever! Like 10x + less buggy as well as easier to debug. It’s easier to debug because I know exactly how the data flows though (as a convention).
Blaze/Session/Template vars/ etc… get to a point of spaghetti where it feels like you’re playing whack a mole. You fix one thing and then 2 days later to realize it broke the app somewhere else unexpectedly. It’s very fast to create UI but you lose time as the app grows.
That being said it’s not a silver bullet. It just helps me a lot so i’m sticking with it, even for small apps (there are other shiny hipster toys like Om and Elm that are cooler and more fun but this combo gets work done).