Thanks for putting this together, always interesting to see people use React for the first time! I did a code review of sorts and cleaned up the code to be more idiomatic React. You can find the series of commits with in-depth comments on GitHub [1]. I may even write this up as a blog post on my website [2].
In short:
- Don't pass around components and call methods on them; prefer to pass props instead
- Conditional rendering instead of hiding, exactly as [3]
- Use the JSX harmony transforms
- Declare props
- Use classSet
- setState only needs to include props that change, rest stay the same
I agree with all of these changes. Code-style-wise, I prefer to call the actual handler implementations `handleFoo` as opposed to `onFoo`. It's a very small detail, but it makes code a little easier to sift through (as well as search/replace), because you always know that `onFoo` is a prop (whose implementation is foreign to the component) and `handleFoo` is a method (whose implementation is native to the component).
Not a bad idea. We would typically use _onClick for any component handler methods, so the _ would distinguish it. We have an internal transform that mangles anything in a module starting with _ so that it cannot be accessed outside.
Absolutely! It is really hard to write idiomatic code your first time through with a framework. No need to feel silly at all. No way I would have spotted these things if I hadn't been using React every day for the past year or so!
>Use the JSX harmony transforms
Thank you for flagging the --harmony flag in the JSX compiler. Just now I was testing Google traceur and es6-module-transpiler and did not realise I already have some of that available for free. I couldn't find any specific information on what subset of ES6 is supported the JSX compiler - would you have a link outlining that?
True, but if you're using JSX on the server side, the dependency doesn't really cost anything. JSTransform's intended purpose, as far as I can see, is as a general-purpose syntax transformer (the ES6 transforms, of which there is only a handful, come as a bonus), whereas Traceur is a dedicated transpiler that is intended to be a complete implementation of ES6.
> I first tried to do this: [...] ...which actually worked, but generated a React error message about an unmounted component.
I suspect that you were doing something wrong that triggered this error. Unmounting components based on state is perfectly idiomatic React, and I do it all the time:
{this.state.mode === 'map' && <Map/>}
You pay for the added DOM work, of course, but this is usually negligible in my experience, especially in your case. You do have to make sure you follow the component lifecycle so that you don't try to use getDOMNode() or similar with a component that is not currently mounted.
It's primarily client-side, but React components output a virtual representation of the DOM, so it's relatively simple to render a page on the server and return HTML.
It's a client-side framework. You'll generally run the JSX preprocessor as part of your website's build process (i.e. before uploading it to a server).
I see some criticism here but I think it is worth pointing out this looks like a person learning to use a new technology and sharing their experience, which is great.
Sometimes that means using non-idiomatic constructs or just having some rough edges. Please be considerate.
I'm not particularly fond of the way React mixes presentation (returning nodes in render()) and logic. Particularly things like:
var classes = _.reduce(["flipped","correct","wrong"],function(m,c){return m+(this.state[c]?c+" ":"");},"",this);
seem very inelegant compared to say, Angular's ngClass, which does the same thing in a data-driven way. But, that's not to say Angular is free from template logic either.
I think the React authors agree that React classes shouldn't contain excessive logic; if your class does, consider extracting it to somewhere more appropriate.
Oh, indeed, I've completely missed the classSet plugin! That would indeed make the code more elegant. And fair point about the logic perhaps being too complicated here.
I find that the ability to trivially make the equivalent of Rails "helper" functions as auxiliary methods on the Component class actually tends to encourage separation of logic - it's the same file so there's no context switch needed. On top of that, since JSX makes ternary statements look much more elegant than bracketed if statements (whose conditions can be a great hiding place for complex logic) it further encourages breaking your logic out into auxiliary functions.
React has a solution for that which actually automatically applies class names as components are inserted and removed: http://facebook.github.io/react/docs/animation.html. It's not perfect, and it's better than doing it manually.
I touch on this in a post - I did try the latter, but got a React warning in the console about unmounted components. That, together with a comment in the official docs, made me go with the show/hide approach.
Although as pointed out in the Disqus comment, choosingg what to render is also fine, I probably did something silly stemming from not fully understanding the component life cycle.
Same, I can see the words (backwards) before clicking a tile. Chrome works fine, except it seems like after a match the first click on a tile doesn't do anything, and I have to click again to make it flip.
The not doing anything is intentional - only when the pair is resolved and the status row goes back to saying "choose a tile" can you click a new tile. This "feature" really needs to be communicated better though, sorry abouy that.
In short:
- Don't pass around components and call methods on them; prefer to pass props instead
- Conditional rendering instead of hiding, exactly as [3]
- Use the JSX harmony transforms
- Declare props
- Use classSet
- setState only needs to include props that change, rest stay the same
[1] https://github.com/ianobermiller/reactexperiment/commits/
[2] http://ianobermiller.com
[3] https://news.ycombinator.com/item?id=8247422