├── CNAME ├── apple-touch-icon.png ├── favicon.ico ├── images └── me.jpeg ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon-96x96.png ├── favicon-160x160.png ├── favicon-192x192.png ├── img ├── ModernReact.jpg ├── BuildingInteractive-001.png ├── BuildingInteractive-002.png ├── BuildingInteractive-003.png ├── BuildingInteractive-004.png ├── webpack-production │ ├── after.png │ └── before.png ├── playing-with-react-and-d3 │ ├── plot_points.png │ ├── basic_render.png │ └── complete_chart.png └── 10x-react-performance │ ├── performance-benchmark-1.png │ └── performance-benchmark-2.png ├── apple-touch-icon-114x114.png ├── apple-touch-icon-120x120.png ├── apple-touch-icon-144x144.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-57x57.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-72x72.png ├── apple-touch-icon-76x76.png ├── _includes ├── navigation.html ├── footer.html ├── post_footer.html ├── header.html ├── pagination.html ├── social_links.html ├── share_buttons.html └── head.html ├── README.md ├── .gitignore ├── css └── pixyll.scss ├── pages ├── about.md └── contact.md ├── _layouts ├── page.html ├── center.html ├── default.html └── post.html ├── _posts ├── 2014-10-20-about.md ├── 2015-08-15-automate-your-home.md ├── 2015-07-29-alt-instances.md ├── 2014-10-20-contact.md ├── 2014-12-29-thanks.md ├── 2015-03-11-i-hear-you-want-a-react-europe-ticket.md ├── 2014-11-28-react-conf-ticket-giveaway.md ├── 2015-01-02-react-conf-giveaway-winner.md ├── 2014-10-13-what-is-this.md ├── 2015-05-24-es6-gotchas.md ├── 2015-08-07-roundup-august-7.md ├── 2017-03-06-the-diverse-react-navigation-ecosystem.md ├── 2014-10-20-tweets-week-in-reactjs-october-20th.md ├── 2016-01-03-NgRepeat-Equivalent-in-React.md ├── 2016-03-14-redux-middleware.md ├── 2014-10-20-this-week-in-react-october-17th.md ├── 2017-03-07-component-kits-for-react-native.md ├── 2014-10-28-twir-a-conference-is-coming.md ├── 2014-11-04-this-week-in-tweets.md ├── 2015-09-19-testing-the-easy-way.md ├── 2015-01-31-react-conf-recap.md ├── 2016-01-28-react-and-ag-grid.md ├── 2015-01-01-isomorphic-javascript-with-react-node.md ├── 2015-07-29-modals-in-react.md ├── 2017-03-28-proxies-with-redux-types.md ├── 2015-11-30-structuring-react-projects.md ├── 2016-04-07-how-to-make-your-react-apps-10x-faster.md ├── 2016-09-28-routing-in-react-native-with-jake-murzy.md ├── 2014-12-27-react-style-guide-patterns-i-like.md ├── 2016-01-15-bring-your-animations-to-life-with-physics.markdown ├── 2014-11-06-the-state-of-flux.md ├── 2015-08-06-composing-components.md ├── 2015-12-01-building-a-react-based-application.md └── 2016-03-13-webpack-in-production.md ├── 404.md ├── index.html ├── feed.xml ├── LICENSE.txt ├── _config.yml └── _sass ├── _solarized-dark.scss ├── _solarized-light.scss └── _main.scss /CNAME: -------------------------------------------------------------------------------- 1 | reactjsnews.com -------------------------------------------------------------------------------- /apple-touch-icon.png: -------------------------------------------------------------------------------- 1 | apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon.ico -------------------------------------------------------------------------------- /images/me.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/images/me.jpeg -------------------------------------------------------------------------------- /favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon-16x16.png -------------------------------------------------------------------------------- /favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon-32x32.png -------------------------------------------------------------------------------- /favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon-96x96.png -------------------------------------------------------------------------------- /favicon-160x160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon-160x160.png -------------------------------------------------------------------------------- /favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/favicon-192x192.png -------------------------------------------------------------------------------- /img/ModernReact.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/ModernReact.jpg -------------------------------------------------------------------------------- /apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /img/BuildingInteractive-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/BuildingInteractive-001.png -------------------------------------------------------------------------------- /img/BuildingInteractive-002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/BuildingInteractive-002.png -------------------------------------------------------------------------------- /img/BuildingInteractive-003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/BuildingInteractive-003.png -------------------------------------------------------------------------------- /img/BuildingInteractive-004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/BuildingInteractive-004.png -------------------------------------------------------------------------------- /img/webpack-production/after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/webpack-production/after.png -------------------------------------------------------------------------------- /img/webpack-production/before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/webpack-production/before.png -------------------------------------------------------------------------------- /_includes/navigation.html: -------------------------------------------------------------------------------- 1 | About 2 | Contact 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReactJSNews 2 | 3 | Open for contributions! Create a PR with a link to your blog post, or include the text in the PR itself. 4 | -------------------------------------------------------------------------------- /img/playing-with-react-and-d3/plot_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/playing-with-react-and-d3/plot_points.png -------------------------------------------------------------------------------- /img/playing-with-react-and-d3/basic_render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/playing-with-react-and-d3/basic_render.png -------------------------------------------------------------------------------- /img/playing-with-react-and-d3/complete_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/playing-with-react-and-d3/complete_chart.png -------------------------------------------------------------------------------- /img/10x-react-performance/performance-benchmark-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/10x-react-performance/performance-benchmark-1.png -------------------------------------------------------------------------------- /img/10x-react-performance/performance-benchmark-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Legitcode/ReactJSNews/HEAD/img/10x-react-performance/performance-benchmark-2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the config file that's used for gh-pages. 2 | _config.gh-pages.yml 3 | _site/ 4 | .sass-cache/ 5 | node_modules/ 6 | .DS_Store 7 | Gemfile.lock 8 | npm-debug.log 9 | -------------------------------------------------------------------------------- /css/pixyll.scss: -------------------------------------------------------------------------------- 1 | --- 2 | # The scss file which include files from _sass/ 3 | --- 4 | 5 | @charset "utf-8"; 6 | 7 | @import "basscss"; 8 | @import "main"; 9 | @import "solarized-dark"; 10 | -------------------------------------------------------------------------------- /pages/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: About 4 | permalink: /about/ 5 | --- 6 | 7 | ReactJSNews is a community driven site. Anyone is welcome to contribute by sending a pull request [on github](https://github.com/Legitcode/ReactJSNews/). -------------------------------------------------------------------------------- /pages/contact.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Contact 4 | permalink: /contact/ 5 | --- 6 | 7 | ReactJSNews is a community driven site. Anyone is welcome to contribute by sending a pull request [on github](https://github.com/Legitcode/ReactJSNews/). 8 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 |
6 |

{{ page.title }}

7 |
8 |
9 | {{ content }} 10 |
11 |
-------------------------------------------------------------------------------- /_posts/2014-10-20-about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "About" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-10-20 19:14 7 | published: true 8 | categories: react 9 | --- 10 | Will write this soon.... 11 | 12 | 13 | 14 | Will write this soon.... 15 | -------------------------------------------------------------------------------- /_posts/2015-08-15-automate-your-home.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Automating your home with node.js and React.js" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2015-08-15 14:00 7 | published: false 8 | categories: react, modal 9 | --- 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /404.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: center 3 | permalink: /404.html 4 | --- 5 | 6 | # 404 7 | 8 | Sorry, we can't seem to find this page's pixylls. 9 | 10 |
11 | Home 12 | Contact 13 |
14 | -------------------------------------------------------------------------------- /_posts/2015-07-29-alt-instances.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Introduction to Alt Instances" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2015-07-29 14:00 7 | published: false 8 | categories: react, alt 9 | --- 10 | 11 | After going through a few different flux-based frameworks, I have (for now) settled on Alt and building flux instances with it. 12 | 13 | 14 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /_includes/post_footer.html: -------------------------------------------------------------------------------- 1 |
2 | John Otander 3 |

4 | Pixyll is an open-source Jekyll theme that's built by John Otander. 5 | When he's not writing code and building things, he likes to ski. A. Lot. 6 |

7 |

8 | Follow him on Twitter. 9 |

10 |
11 | -------------------------------------------------------------------------------- /_posts/2014-10-20-contact.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Contact" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-10-20 19:15 7 | published: true 8 | categories: react 9 | --- 10 | For now, you can leave a comment anywhere on this site or tweet us [@ReactJSNews](http://twitter.com/reactjsnews). 11 | 12 | 13 | 14 | For now, you can leave a comment anywhere on this site or tweet us [@ReactJSNews](http://twitter.com/reactjsnews). 15 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /_posts/2014-12-29-thanks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Thanks for Subscribing!" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-12-29 17:59 7 | published: true 8 | categories: react 9 | --- 10 | You're going to love the content in this newsletter. All that's left is to confirm your subscription by checking your email! 11 | 12 | 13 | 14 | You're going to love the content in this newsletter. All that's left is to confirm your subscription by checking your email! 15 | -------------------------------------------------------------------------------- /_layouts/center.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 |
6 | {% include header.html %} 7 | 8 |
9 |
10 | 11 | {{ content }} 12 |
13 |
14 |
15 | 16 | {% include footer.html %} 17 | 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 | 7 |
8 | {% for post in paginator.posts %} 9 |
10 | 11 |

{{ post.title }}

12 |

13 | {% if post.summary %} 14 | {{ post.summary }} 15 | {% else %} 16 | {{ post.excerpt }} 17 | {% endif %} 18 |

19 | Read More 20 |
21 | {% endfor %} 22 |
23 | 24 | {% include pagination.html %} 25 |
26 | -------------------------------------------------------------------------------- /_includes/pagination.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | --- 4 | 5 | 6 | 7 | {{ site.title | xml_escape }} 8 | {{ site.description | xml_escape }} 9 | {{ site.url }}{{ site.baseurl }}/ 10 | 11 | {% for post in site.posts limit:10 %} 12 | 13 | {{ post.title | xml_escape }} 14 | {{ post.content | xml_escape }} 15 | {{ post.date | date: "%a, %d %b %Y %H:%M:%S %z" }} 16 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 17 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 18 | 19 | {% endfor %} 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 John Otander 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Site settings 2 | title: ReactJS News 3 | email: zackify@gmail.com 4 | author: Zach Silveira 5 | description: "ReactJS News!" 6 | baseurl: "" 7 | url: "https://reactjsnews.com" 8 | 9 | # Google analytics 10 | google_analytics: "UA-55670732-1" 11 | 12 | # Optional features 13 | animated: true 14 | show_related_posts: false 15 | show_post_footers: false 16 | 17 | # Disqus post comments 18 | # (leave blank to disable Disqus) 19 | disqus_shortname: "reactjsnews" 20 | 21 | # Social icons 22 | show_social_icons: false 23 | github_username: 24 | stackoverflow_id: 25 | twitter_username: 26 | google_plus_id: 27 | linkedin_username: 28 | angellist_username: 29 | bitcoin_url: 30 | paypal_url: 31 | flattr_button: 32 | 33 | # Post sharing icons 34 | show_sharing_icons: false 35 | share_text: 'Share this post!' 36 | # Change to 'true' to enable individual icons 37 | share_facebook: false 38 | share_twitter: false 39 | share_googleplus: false 40 | share_linkedin: false 41 | share_digg: false 42 | share_tumblr: false 43 | share_reddit: false 44 | share_stumbleupon: false 45 | share_hackernews: false 46 | 47 | # Build settings 48 | markdown: kramdown 49 | redcarpet: 50 | extensions: ['smart', 'tables', 'with_toc_data'] 51 | permalink: :title 52 | paginate: 10 53 | gems: [jekyll-paginate] 54 | sass: 55 | compressed: true 56 | -------------------------------------------------------------------------------- /_posts/2015-03-11-i-hear-you-want-a-react-europe-ticket.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "I Hear You Want A React Europe Ticket!" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2015-03-11 22:44 7 | published: true 8 | categories: react 9 | --- 10 | The React Europe team has been kind enough to offer me two tickets. One for me to use, and another to giveaway. I'm excited about this conference, but I'm not 100% sure yet if I'll be going. Either way, someone will win a ticket. If I do end up being able to go, I'll be helping at the check in booth, so anyone who didn't see me at the first conference definitely would this time! 11 | 12 | 13 | 14 | The React Europe team has been kind enough to offer me two tickets. One for me to use, and another to giveaway. I'm excited about this conference, but I'm not 100% sure yet if I'll be going. Either way, someone will win a ticket. If I do end up being able to go, I'll be helping at the check in booth, so anyone who didn't see me at the first conference definitely would this time! 15 | 16 | ##The Details 17 | 18 | I'm going to give it away similar to last time, but the criteria is going to be much simpler. Whichever article I consider to be the most influential and impactful will win. It's that simple. You can submit an article or video. It just has to be a minimum of 300 words and high quality. The video needs to be useful as well, obviously a two-second video won't be accepted. If you have any questions, leave a comment! You can send in your submissions to: zackify(at)gmail.com! 19 | 20 | **Deadline:** May 1st 21 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 |
6 | {% include header.html %} 7 | 8 |
9 | 24 |
25 |
26 | 27 | {% include footer.html %} 28 | 29 | 30 | -------------------------------------------------------------------------------- /_includes/social_links.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% if site.github_username %} 4 | 5 | {% endif %} 6 | {% if site.stackoverflow_id %} 7 | 8 | {% endif %} 9 | 10 | {% if site.twitter_username %} 11 | 12 | {% endif %} 13 | {% if site.google_plus_id %} 14 | 15 | {% endif %} 16 | {% if site.email %} 17 | 18 | {% endif %} 19 | {% if site.linkedin_username %} 20 | 21 | {% endif %} 22 | {% if site.angellist_username %} 23 | 24 | {% endif %} 25 |
26 |
27 | {% if site.bitcoin_url %} 28 | 29 | {% endif %} 30 | {% if site.paypal_url %} 31 | 32 | {% endif %} 33 | {% if site.flattr_button %} 34 | {{ site.flattr_button }} 35 | {% endif %} 36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /_posts/2014-11-28-react-conf-ticket-giveaway.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "React Conf Ticket Giveaway" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-11-28 15:09 7 | published: true 8 | categories: react 9 | --- 10 | The first ever React conference is happening in January at Facebook's headquarters. The sad part is that the demand is so high, not everyone who wants to go will be able to. This is part of the reason I'll be giving away a ticket. The other reason is to create more tutorials and guides for the community. You're probably wondering what that has to do with a giveaway, but you're about to find out! 11 | 12 | 13 | 14 | The first ever React conference is happening in January at Facebook's headquarters. The sad part is that the demand is so high, not everyone who wants to go will be able to. This is part of the reason I'll be giving away a ticket. The other reason is to create more tutorials and guides for the community. You're probably wondering what that has to do with a giveaway, but you're about to find out! 15 | 16 | ##The Details 17 | 18 | There's a few small guidelines I have. If you're interested in getting a free ticket you need to do one of two things: 19 | 20 | **Create a Blog Post** 21 | 22 | - Must be at least 300 words, excluding code examples 23 | - It has to be completely original 24 | - You must be okay with me posting it on this site, credit will be given to the author. 25 | 26 | **Make a video** 27 | 28 | If blogging isn't your thing, you have the option of creating a video tutorial. 29 | 30 | - It must be at least five minutes long 31 | - needs to have the source code available 32 | 33 | ##Conclusion 34 | 35 | I hope to see everyone at the conference, so please try to make it out! Just to make sure everyone understands, this is only a giveaway for a ticket, not a flight, room, or anything else. You can submit your article or video to zackifyatgmail.com. They must be unique and not something you've already made. Leave a comment with any questions or tweet [@ReactJSNews](http://twitter.com/ReactJSNews)! 36 | -------------------------------------------------------------------------------- /_posts/2015-01-02-react-conf-giveaway-winner.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "React Conf Giveaway Winner" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2015-01-02 13:39 7 | published: true 8 | categories: react 9 | --- 10 | I would like to thank everybody that entered the giveaway. It was a lot harder than I thought it would be to choose a winner. I know that everyone who entered tried very hard. Before going into who won, here's a little recap of what was submitted. 11 | 12 | 13 | 14 | I would like to thank everybody that entered the giveaway. It was a lot harder than I thought it would be to choose a winner. I know that everyone who entered tried very hard. Before going into who won, here's a little recap of what was submitted. 15 | 16 | **David Wells** wrote about [Isomorphic React](https://reactjsnews.com/isomorphic-javascript-with-react-node/) utilizing the power of node to keep consistent code on both the client and server. 17 | 18 | **James Burnett** Submitted two articles, [Complex Drag and Drop in React](https://reactjsnews.com/complex-drag-and-drop-lists-using-react/) and [Setting up React with Rails and Jest](https://reactjsnews.com/setting-up-rails-for-react-and-jest/). 19 | 20 | [**David Chang**](http://davidandsuzi.com/), who previously wrote the insanely popular [State of Flux](https://reactjsnews.com/the-state-of-flux/), submitted [React Style Guide](https://reactjsnews.com/react-style-guide-patterns-i-like/). 21 | 22 | [**Jack Callister**](http://jackcallister.com/) wrote about [building a test suite in React](https://reactjsnews.com/building-a-test-suite-in-react-js/). 23 | 24 | Only three people submitted, which made it even harder to choose a winner. When starting this giveaway I didn't really have a clear idea on how I was going to grade the articles. I ended up deciding that I should let whoever had the most influencial article win. Due to this, the winner is **David Chang**. His article on React style patterns, in a span of two days, holds over 35% of all pageviews on this site. It was also on the front page of [Hacker News](http://news.ycombinator.com). 25 | 26 | ##### Conclusion 27 | 28 | I would just like to say thanks to all four of you for entering the giveaway. The community is better off with the guides you have each written! 29 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | {% assign minutes = content | number_of_words | divided_by: 180 %} 6 | {% if minutes == 0 %} 7 | {% assign minutes = 1 %} 8 | {% endif %} 9 | 10 |
11 |

{{ page.title }}

12 | {{ page.date | date: "%b %-d, %Y" }} 13 | {% if page.author %} 14 | {% if page.author_url %} 15 | by {{ page.author }} 16 | {% else %} 17 | by {{ page.author }} 18 | {% endif %} 19 | {% endif %} 20 |
21 | {% if page.update_date %} 22 | Updated: {{ page.update_date | date: "%b %-d, %Y" }}
23 | {% endif %} 24 | {{ minutes }} minute read 25 |
26 | 27 |
28 | {{ content | split:'' | last }} 29 |
30 | 31 | {% if site.show_sharing_icons %} 32 | {% include share_buttons.html %} 33 | {% endif %} 34 | 35 | {% if site.show_post_footers %} 36 | {% include post_footer.html %} 37 | {% endif %} 38 | 39 | {% if site.disqus_shortname %} 40 |
41 | 50 | 51 | {% endif %} 52 | 53 | {% if site.show_related_posts %} 54 |

Related Posts

55 | {% for post in site.related_posts %} 56 |
57 | 58 |

{{ post.title }}

59 |

{{ post.summary }}

60 |
61 |
62 | {% endfor %} 63 | {% endif %} 64 | -------------------------------------------------------------------------------- /_includes/share_buttons.html: -------------------------------------------------------------------------------- 1 |
2 | {{ site.share_text }} 3 | 4 | 43 |
44 | -------------------------------------------------------------------------------- /_posts/2014-10-13-what-is-this.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "We're Back!" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | author_url: http://zach.codes 7 | date: 2014-10-13 00:05 8 | published: true 9 | categories: react 10 | --- 11 | As some of you may know, ReactJS News started out as a hacker news type site focused on letting anyone post links to their latest React creations. A couple months back, I had to travel and didn't have internet access for a few months. During this time the server crashed, we were using a meteor app just by doing `meteor up`, pretty stupid, I know. Now that I'm back, myself and [Jorge](https://github.com/vasco3) are working on making this site more awesome than it ever was. 12 | 13 | 14 | 15 | As some of you may know, ReactJS News started out as a hacker news type site focused on letting anyone post links to their latest React creations. A couple months back, I had to travel and didn't have internet access for a few months. During this time the server crashed, we were using a meteor app just by doing `meteor up`, pretty stupid, I know. Now that I'm back, myself and [Jorge](https://github.com/vasco3) are working on making this site more awesome than it ever was. 16 | 17 | ##What's Coming 18 | The new landing page is a dedicated blog running [Ghost](http://ghost.org). I plan to personally post a collection of the latest React news every week. I know that the official React blog ran by [@Vjeux](https://twitter.com/vjeux) also does this, but he's even told me he hardly has time to do it. I'm looking for more people interested in React to become a contributor. If anyone is interested, please tweet us [@ReactJSNews](http://twitter.com/ReactJSNews). 19 | Next up, Jorge and I are working on a custom content management system built using React and Flux that will handle our community section. It's aimed to be just like Hacker News. You can star it on github and even help with the development if you're interested, the repo is [here](https://github.com/Legitcode/ReactJSNews). Since this site is running on a VM, we might add an IRC server, Minecraft, or something else if the community wants us to. 20 | 21 | ##Anything Else? 22 | That's about it for now. I would like to feature some React video tutorials that people have made. I've also been thinking of making some myself. If you like this project, please follow us on Twitter or leave a comment with some suggestions! 23 | 24 | Oh yeah, a simple logo for our sidebar would look nice :P 25 | -------------------------------------------------------------------------------- /_posts/2015-05-24-es6-gotchas.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "ES6 Gotchas" 4 | excerpt_separator: 5 | author: Zach Silveira, Robbie dela Victoria 6 | date: 2015-05-25 14:00 7 | published: true 8 | categories: react 9 | --- 10 | 11 | With ES6 components, there are a few "aha" moments and annoyances. This post was created so that you don't have to go through some of the struggles myself and others have gone through. 12 | 13 | 14 | 15 | **Function Bindings** 16 | 17 | ~~~js 18 |
19 | ~~~ 20 | 21 | What's wrong with that? If you're not using `React.createClass`, which autobinds functions, you need to do it yourself. The correct way would be add it to constructor: 22 | 23 | ~~~js 24 | import React from 'react' 25 | 26 | export default class ComponentName extends React.Component { 27 | constructor(){ 28 | super() 29 | this.handleClick = this.handleClick.bind(this) 30 | } 31 | ... 32 | ~~~ 33 | 34 | Another way of dealing with this is by enabling stage 0 in babel to include [es7 classProperties](https://gist.github.com/jeffmo/054df782c05639da2adb) 35 | 36 | **Warning** 37 | Use with extreme caution. Since this is [Stage 0 - Strawman](https://babeljs.io/docs/usage/experimental/). This is subject to change in the future and may require a bit of rewrite of your code. 38 | 39 | The idea is to combine fat arrow syntax which automatically binds to this. A more detailed explanation can be found [here](http://www.ian-thomas.net/autobinding-react-and-es6-classes/) 40 | 41 | ~~~js 42 | export default class ComponentName extends React.Component { 43 | ... 44 | handleClick = (e) => { 45 | ... 46 | } 47 | ~~~ 48 | It may seem tempting to use `handler.bind(this)` or the [ES7](https://github.com/zenparsing/es-function-bind) `::` handler syntax to bind handlers in the component's `render()` method. However, this may break the optimization of the `PureRenderMixin` and will create a new function every time the `render()` method is called. 49 | 50 | ~~~js 51 | export default class ComponentName extends React.Component { 52 | 53 | handleClick(e) { 54 | ... 55 | } 56 | 57 | render(){ 58 | return ( 59 | // this will create a new function every 60 | // time the render method is called 61 | 62 | ); 63 | } 64 | } 65 | ~~~ 66 | 67 | 68 | **Static Property Initializers** 69 | 70 | In old-school components, you can do this at the start of your component: 71 | 72 | ~~~js 73 | propTypes: { 74 | field: React.PropTypes.string 75 | } 76 | ~~~ 77 | 78 | In ES6/7 components, you have two options, you can specify them after your component class, like so: 79 | 80 | ~~~js 81 | Component.propTypes = { 82 | //prop validations 83 | } 84 | ~~~ 85 | 86 | Which works fine, but I think doing this is a lot better: 87 | 88 | ~~~js 89 | class Test extends React.Component{ 90 | 91 | static propTypes = { 92 | //validate here 93 | } 94 | 95 | render(){ 96 | //return 97 | } 98 | } 99 | ~~~ 100 | 101 | What's the "gotcha" you might ask? You need to enable **stage 0** babel transforms to use this. 102 | 103 | Have more examples that you would like to add? Please add on to this post by [sending a pull request](https://github.com/Legitcode/ReactJSNews/blob/master/posts/2015-05-24-es6-gotchas.md)! 104 | -------------------------------------------------------------------------------- /_posts/2015-08-07-roundup-august-7.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "React Recap: August 7th" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2015-08-07 13:40 7 | published: true 8 | categories: react, roundup 9 | --- 10 | 11 | I've noticed a lot of roundups lately, but there's a lot of good content people aren't sharing. If you like these types of posts, leave a comment or [Tweet us](http://twitter.com/reactjsnews). 12 | 13 | 14 | 15 | I've noticed a lot of roundups lately, but there's a lot of good content people aren't sharing. If you like these types of posts, leave a comment or [Tweet us](http://twitter.com/reactjsnews). Here's my favorite content found this week. 16 | 17 | ##Reddit 18 | 19 | [Is react rendered on the backend actually faster than templating languages?](https://www.reddit.com/r/reactjs/comments/3ftijc/is_react_rendered_on_the_backend_actually_faster/) 20 | 21 | [Can stores maintain state after their attached components unmount?](https://www.reddit.com/r/reactjs/comments/3fbst3/can_stores_maintain_state_after_their_attached/) 22 | 23 | [Beginner here, can't figure out how to add a message to a chat component](https://www.reddit.com/r/reactjs/comments/3fapu3/beginner_here_cant_figure_out_how_to_add_a/) 24 | 25 | [Best Practice for handling error with react/flux?](https://www.reddit.com/r/reactjs/comments/3g3xj8/question_best_practice_for_handling_error_with/) 26 | 27 | [What's the best beginner resource to learn React?](https://www.reddit.com/r/reactjs/comments/3g3on5/whats_the_best_beginner_resource_to_learn_react/) 28 | 29 | [How do I remove an item from this.state.users?](https://www.reddit.com/r/reactjs/comments/3fuzu6/remove_item_from_thisstateusers/) 30 | 31 | ##Stackoverflow 32 | 33 | [React appends 'px' to stop-opacity css value](http://stackoverflow.com/questions/31858101/react-appends-px-to-stop-opacity-css-value) 34 | 35 | [React, “this”, cloneElement and es6](http://stackoverflow.com/questions/31841949/react-this-cloneelement-and-es6) 36 | 37 | [Do I need Flux Store for this purpose?](http://stackoverflow.com/questions/31868993/do-i-need-flux-store-for-this-purpose) 38 | 39 | ##React Starter Kits 40 | 41 | [React Starter Kit](https://github.com/kriasoft/react-starter-kit) — a skeleton of an "isomorphic" web application / SPA built with React.js, Express, Flux, ES6+, JSX, Babel, PostCSS, Webpack, BrowserSync... 42 | 43 | [react-mobservable-boilerplate](https://github.com/mweststrate/react-mobservable-boilerplate) 44 | 45 | [React UI Builder](https://github.com/ipselon/react-ui-builder) 46 | 47 | [HJS Webpack](https://github.com/henrikjoreteg/hjs-webpack) Helpers/presets for setting up webpack with hotloading react and ES6(2015) using Babel. 48 | 49 | [React Hot Boilerplate](https://github.com/gaearon/react-hot-boilerplate) 50 | 51 | ##Random 52 | 53 | [What the Flux?! Let’s Redux.](https://blog.andyet.com/2015/08/06/what-the-flux-lets-redux) 54 | 55 | [New React Devtools](http://facebook.github.io/react/blog/2015/08/03/new-react-devtools-beta.html) 56 | 57 | [Setting up Vim for React](https://jaxbot.me/articles/setting-up-vim-for-react-js-jsx-02-03-2015) 58 | 59 | [Just rebuilt my portfolio w/ React.js](https://www.designernews.co/stories/53875-show-dn-just-rebuilt-my-portfolio-w-reactjs) 60 | 61 | Don't forget our recent posts: 62 | 63 | [React.Component vs React.createClass](https://reactjsnews.com/composing-components) 64 | 65 | [Modals in React](https://reactjsnews.com/modals-in-react) 66 | -------------------------------------------------------------------------------- /_posts/2017-03-06-the-diverse-react-navigation-ecosystem.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "The Diverse React Navigation Ecosystem" 4 | date: 2017-03-06 17:00 5 | excerpt_separator: 6 | author: Stephen Grider 7 | published: true 8 | categories: react, react native 9 | --- 10 | 11 | The routing ecosystem around React and React Native is quite different. One is characterized by a strong incumbent, and the other is plagued by rapid change. 12 | 13 | 14 | 15 | 16 | ### React JS 17 | 18 | No question about it, React Router ([ReactTraining/react-router](https://github.com/ReactTraining/react-router)) is king here. They have the benefit of several years of active development, along with an active community submitting PR’s, fixes, etc. Supplement that with myriad tutorials and how-to’s and you end up with a well-supported, stable product. To be fair, React Router has suffered some major API upsets, and is nearly the poster-child for javascript fatigue but the maintainers have declared their lasting support for a few specific versions, which means you can plop down with V3 and be good to go for the next 12 to 24 months. 19 | 20 | ### React Native 21 | 22 | Ok, this is where things start to get really, really crazy. The most important thing to keep in mind is that the React Native team has produced three navigation helpers: NavigatorIOS, Navigator, and NavigatorExperimental. 23 | 24 | * NavigatorIOS was quickly deprecated, as it was supported only by (you guessed it) IOS. 25 | * Navigator is the currently endorsed solution for navigation, at least if you are following the official docs. However, its about to be upset by- 26 | * NavigationExperimental. This is an updated navigator that has learned some lessons from Navigator, and has some solid integration with Redux. ‘Navigator’ is (or was!) sleighted to be deprecated in favor of NavigationExperimental at some point. 27 | 28 | Already you have three ‘official’ navigators supported by the React Native team. The big issue with all three of these is that they are somewhat lightweight and don’t include a lot of common navigation situations out of the box, like sidebars, tab bars, headers, etc. To solve that, the community has introduced… 29 | 30 | * React Native Router Flux ([aksonov/react-native-router-flux](https://github.com/aksonov/react-native-router-flux)). My personal favorite, this is router is based upon NavigationExperimental. You can imagine that the authors looked at NavigationExperimental, realized that everyone would be writing the same wrapper code around it, and so created this project. 31 | * React Native Router (t4t5/react-native-router). Haven’t used it, but it is colossally popular. 32 | * React Router Native ([jmurzy/react-router-native](https://github.com/jmurzy/react-router-native)). Strives for API conformity with React Router (the above mentioned one). The great approach here is that they bring in the concept of a URL in native apps, where one doesn’t otherwise exist. This is a great approach that simplifies a lot of common routing situations. 33 | Of course, there’s one more big solution that is supposedly going to become the standard: 34 | * React Navigation ([react-community/react-navigation](https://github.com/react-community/react-navigation)). Seen as a solution that will soon be ‘official’ in the community, it is intended to replaced NavigationExperimental. This package is still in active development, so I expect at least a bit of API upset over the coming months. If you want to use official solutions, go with this, if you want a tried and true solution, go with React Native Router Flux. 35 | -------------------------------------------------------------------------------- /_posts/2014-10-20-tweets-week-in-reactjs-october-20th.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "This Week in Tweets: Oct 21" 4 | excerpt_separator: 5 | author: Ferran Negre 6 | date: 2014-10-20 20:30 7 | published: true 8 | categories: react 9 | --- 10 | I will try to gather all the interesting stuff I've seen during this last week. Feel free to comment and suggest more tweets. 11 | 12 | 13 | 14 | I will try to gather all the interesting stuff I've seen during this last week. Feel free to comment and suggest more tweets. 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 |
42 | -------------------------------------------------------------------------------- /_posts/2016-01-03-NgRepeat-Equivalent-in-React.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Is There a React Equivalent for Angular’s ng-repeat?" 4 | excerpt_separator: 5 | author: Michael Martin 6 | date: 2016-01-03 23:16 7 | published: true 8 | categories: react, angular 9 | --- 10 | 11 | If you're familiar with AngularJS you already understand many of the principles necessary to get started with React. In this post, I'll demonstrate how to write the equivalent of an ngRepeat inside a React component. 12 | 13 | 14 | 15 | This post originally appeared on my [Angular to React](http://angulartoreact.com/ng-repeat-react-equivalent) site where you'll find more resources like this to help Angular Developers get up to speed quickly on React. 16 | 17 | # Is There a React Equivalent for Angular’s ng-repeat? 18 | 19 | #### Yes. React doesn't use a proprietary construct to iterate over a collection of data. Instead, it relies on native Javascript iterators to generate repeating blocks of UI. Keep reading below for code samples and further explanation. 20 | 21 | If you've been developing Angular applications for any amount of time, you've likely used the `ng-repeat` directive. Generating repeating blocks of UI from a data structure is a cornerstone of web development regardless of language or framework. 22 | 23 | The AngularJS team wrapped up a really convenient and powerful piece of iterative magic in the `ng-repeat` directive. With very little code, you can create dynamic lists that stay in sync with a collection of data. Just so we're on the same page, here's what the Angular code looks like: 24 | 25 | ##### AngularJS Code Sample for `ng-repeat` 26 | 27 | Assume you have an array like this: 28 | 29 | ```javascript 30 | var items = [ 31 | { name: "Matthew", link: "https://bible.com/1/mat.1" }, 32 | { name: "Mark", link: "https://bible.com/1/mrk.1" }, 33 | { name: "Luke", link: "https://bible.com/1/luk.1" }, 34 | { name: "John", link: "https://bible.com/1/jhn.1" } 35 | ]; 36 | ``` 37 | 38 | In Angular 1.x, to create a `ul` with an `li` for each item in the array you would put the following code in your controller: 39 | 40 | ```javascript 41 | .controller("NgRepeatDemoCtrl", function($scope) { 42 | $scope.items = items; 43 | }); 44 | ``` 45 | 46 | Then, in your view, you could use the `ng-repeat` directive like this: 47 | 48 | ```html 49 | 54 | ``` 55 | 56 | ##### React Alternative to `ng-repeat` 57 | 58 | To perform the same task in React you just need to think natively. Under the hood `ng-repeat` is just using a native Javascript iterator. You can use the same sort of native iterator directly in React. For just example, I'll use `Array.map`. Here's an example: 59 | 60 | ```javascript 61 | var RepeatModule = React.createClass({ 62 | getDefaultProps: function() { 63 | return { items: [] } 64 | }, 65 | render: function() { 66 | 67 | var listItems = this.props.items.map(function(item) { 68 | return ( 69 |
  • 70 | {item.name} 71 |
  • 72 | ); 73 | }); 74 | 75 | return ( 76 | 79 | ); 80 | } 81 | }); 82 | ``` 83 | 84 | In this example, `Array.map` iterates through every item contained in `items` and executes a function that returns a DOM element. _(Technically, it's a virtual DOM element, but that's a different discussion.)_   Every `li` that is returned from inside of the map function gets added to a new array and finally returned as the value of the `Array.map()` function. The result of that function is stored in the `listItems` variable. When React calls the render method on our component, we generate an array of list items and then insert them into our `ul` using a single pair of enclosing curly braces. 85 | 86 | ##### Try It Out Yourself Using [This JSFiddle](http://jsfiddle.net/zqef96hu/2/) 87 | -------------------------------------------------------------------------------- /_posts/2016-03-14-redux-middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Building Redux Middleware" 4 | date: 2016-03-14 12:00:09 +1300 5 | excerpt_separator: 6 | author: Zach Silveira 7 | published: true 8 | categories: react, webpack 9 | --- 10 | 11 | After writing my post a few months ago on [building your own redux app](https://reactjsnews.com/your-first-redux-app), I have been asked a couple times to write a guide on creating redux middleware and how it works. This will be a quick post on how you can acheive anything with your own middleware! 12 | 13 | 14 | 15 | ##Basic middleware 16 | 17 | ```js 18 | 19 | const customMiddleware = store => next => action => { 20 | if(action.type !== 'custom') return next(action) 21 | //do stuff! 22 | } 23 | ``` 24 | 25 | Applying it: 26 | 27 | ```js 28 | import { createStore, applyMiddleware, } from 'redux' 29 | import reducer from './reducer' 30 | import customMiddleware from './customMiddleware' 31 | 32 | const store = createStore( 33 | reducer, 34 | applyMiddleware(customMiddleware) 35 | ) 36 | ``` 37 | 38 | Whaaa? `store => next => action =>` I know that looks confusing. Essentially you are building a chain of functions, it will look like this when it gets called: 39 | 40 | ```js 41 | //next looks something like this: 42 | let dispatched = null 43 | let next = actionAttempt => dispatched = actionAttempt 44 | 45 | const dispatch = customMiddleware(store)(next) 46 | 47 | dispatch({ 48 | type: 'custom', 49 | value: 'test' 50 | }) 51 | ``` 52 | 53 | All you are doing is chaining function calls and passing in the neccesary data. When I first saw this I was confused a little due to the long chain, but it made perfect sense after reading the article on [writing redux tests](http://redux.js.org/docs/recipes/WritingTests.html). 54 | 55 | So now that we understand how those chained functions work, let's explain the first line of our middleware. 56 | 57 | ```js 58 | if(action.type !== 'custom') return next(action) 59 | ``` 60 | 61 | There should be some way to tell what actions should go through your middleware. In this example, we are saying if the action's type is not `custom` call next, which will pass it to any other middleware and then to the reducer. 62 | 63 | ##Doing Cool stuff 64 | 65 | The official guide on [redux middleware](http://redux.js.org/docs/advanced/Middleware.html) covers a few examples on this, I'm going to try to explain it in a more simple way. 66 | 67 | Say we want an action like this: 68 | 69 | ```js 70 | dispatch({ 71 | type: 'ajax', 72 | url: 'http://api.com', 73 | method: 'POST', 74 | body: state => ({ 75 | title: state.title 76 | description: state.description 77 | }), 78 | cb: response => console.log('finished!', response) 79 | }) 80 | 81 | ``` 82 | 83 | We want this to do a post request, and then call the `cb` function. It would look something like this: 84 | 85 | ```js 86 | import fetch from 'isomorphic-fetch' 87 | 88 | const ajaxMiddleware = store => next => action => { 89 | if(action.type !== 'ajax') return next(action) 90 | 91 | fetch(action.url, { 92 | method: action.method, 93 | body: JSON.stringify(action.body(store.getState())) 94 | }) 95 | .then(response => response.json()) 96 | .then(json => action.cb(json)) 97 | } 98 | ``` 99 | 100 | It's pretty simple really. You have access to every method redux offers in middleware. What if we wanted the `cb` function to have access to dispatching more actions? We could change that last line of the fetch function to this: 101 | 102 | ```js 103 | .then(json => action.cb(json, store.dispatch)) 104 | ``` 105 | 106 | Now in the callback, we can do: 107 | 108 | ```js 109 | cb: (response, dispatch) => dispatch(newAction(response)) 110 | 111 | ``` 112 | 113 | As you can see, middleware is very easy to write in redux. You can pass store state back to actions, and so much more. If you need any help or if I didn't go into detail enough, feel free to leave a comment below! 114 | -------------------------------------------------------------------------------- /_posts/2014-10-20-this-week-in-react-october-17th.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "This Week in React: Oct 20" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-10-20 18:22 7 | published: true 8 | categories: react 9 | tags: twir 10 | --- 11 | This is the first weekly roundup on ReactJS News! We've been busy working on making this site awesome for you guys, and it's coming along. Let's get started. 12 | 13 | 14 | 15 | This is the first weekly roundup on ReactJS News! We've been busy working on making this site awesome for you guys, and it's coming along. Let's get started. 16 | 17 | ##React DnD 18 | First off, we've got a [React Drag n' drop library](https://github.com/gaearon/react-dnd). I've had to make something like this at work, but this would have been so much easier to use. Creating a drop target with this mixin is very easy, as we can see from its documentation: 19 | 20 | ~~~js 21 | var { DragDropMixin } = require('react-dnd'), 22 | ItemTypes = require('./ItemTypes'); 23 | 24 | var ImageBlock = React.createClass({ 25 | mixins: [DragDropMixin], 26 | 27 | configureDragDrop(registerType) { 28 | 29 | registerType(ItemTypes.IMAGE, { 30 | 31 | // dropTarget, when specified, is { acceptDrop(item)?, canDrop(item)? enter(item)?, over(item)?, leave(item)? } 32 | dropTarget: { 33 | acceptDrop(image) { 34 | // Do something with image! for example, 35 | DocumentActionCreators.setImage(this.props.blockId, image); 36 | } 37 | } 38 | }); 39 | }, 40 | 41 | render() { 42 | 43 | // {...this.dropTargetFor(ItemTypes.IMAGE)} will expand into 44 | // { onDragEnter: (handled by mixin), onDragOver: (handled by mixin), onDragLeave: (handled by mixin), onDrop: (handled by mixin) }. 45 | 46 | return ( 47 |
    48 | {this.props.image && 49 | 50 | } 51 |
    52 | ); 53 | } 54 | ); 55 | ~~~ 56 | 57 | Want to play around with it? Check out [this JSFiddle](http://jsbin.com/sutopepobu/1/edit?html,js,output)! 58 | ##Morearty.js 59 | [Morearty.js](https://github.com/moreartyjs/moreartyjs) aims to help those who need more advanced state handling in React. What's cool is that component state is transferred to sub-components in a binding attribute and can be retrieved using a custom method. This can be really useful when you have two components interacting together. Creating states (contexts) in morearty is pretty simple: 60 | 61 | ~~~js 62 | var Ctx = Morearty.createContext( 63 | { // initial state 64 | nowShowing: 'all', 65 | items: [{ 66 | title: 'My first task', 67 | completed: false, 68 | editing: false 69 | }] 70 | }, 71 | { // configuration 72 | requestAnimationFrameEnabled: true 73 | } 74 | ); 75 | ~~~ 76 | 77 | Take a look at [the docs](https://github.com/moreartyjs/moreartyjs) for more information. 78 | 79 | That's all that was sent in this week. I've been super busy trying to get our news section up and running. It's been hard since I just took on a second job. Please send in anything you make to our Twitter [@ReactJSNews](http://twitter.com/reactjsnews). Before you leave, take a look at some of these React articles I found interesting this week: 80 | 81 | - [Swarm.js+React — real-time, offline-ready Holy Grail web apps](http://swarmjs.github.io/articles/todomvc/) 82 | - [React Art - drawing vectors in React](https://github.com/reactjs/react-art) 83 | - [Learning React.js: Getting Started and Concepts](http://scotch.io/tutorials/javascript/learning-react-getting-started-and-concepts) 84 | 85 | **Interesting Stackoverflow Posts** 86 | 87 | - [Flux: return values from AJAX to the component](http://stackoverflow.com/questions/26451659/flux-return-values-from-ajax-to-the-component) 88 | - [What is the best way for interacting between Components in Reactjs?](http://stackoverflow.com/questions/26407273/what-is-the-best-way-for-interacting-between-components-in-reactjs) 89 | - [How to reset a React component?](http://stackoverflow.com/questions/26358144/how-to-reset-a-reactjs-element) 90 | - [In single page apps, is it standard to do sorting and filtering on the server?](http://stackoverflow.com/questions/26352300/in-single-page-apps-is-it-standard-to-do-sorting-and-filtering-on-the-server) 91 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% if page.title %}{{ page.title | strip_html }} – {% endif %}{{ site.title | strip_html }} 5 | 6 | 7 | 8 | 9 | {% if page.categories %}{% endif %} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% if site.show_social_icons or site.show_sharing_icons %} 19 | 20 | {% endif %} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 56 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /_posts/2017-03-07-component-kits-for-react-native.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Component Kits for React Native" 4 | date: 2017-03-07 17:00 5 | excerpt_separator: 6 | author: Stephen Grider 7 | published: true 8 | categories: react, react native 9 | --- 10 | 11 | You won’t find as many styling solutions for React Native as you will for React JS. This stems from two simple realities: 12 | 13 | 1. React Native is a much smaller target for component libraries than traditional CSS frameworks. In other words, Bootstrap CSS can be used with any web framework, whereas component libraries for React Native only work with…you guessed it…React Native. 14 | 2. Customizing React Native styling isn’t the easiest thing in the world. Many apps demand custom styling, which makes component kits not too useful. In addition, it is challenging to customize each and every component, as the flexibility that you gain with traditional CSS on the web doesn’t carry over easily to component libraries. 15 | 16 | With that said, here are a few options. 17 | 18 | 19 | 20 | 21 | You won’t find as many styling solutions for React Native as you will for React JS. This stems from two simple realities: 22 | 23 | 1. React Native is a much smaller target for component libraries than traditional CSS frameworks. In other words, Bootstrap CSS can be used with any web framework, whereas component libraries for React Native only work with…you guessed it…React Native. 24 | 2. Customizing React Native styling isn’t the easiest thing in the world. Many apps demand custom styling, which makes component kits not too useful. In addition, it is challenging to customize each and every component, as the flexibility that you gain with traditional CSS on the web doesn’t carry over easily to component libraries. 25 | 26 | With that said, here are a few options. 27 | 28 | ### NativeBase - [Essential cross-platform UI components for React Native](http://nativebase.io/) 29 | 30 | A huge collection of components, most of which look quite nice. That’s the plus side. The down side is that some of the components are somewhat buggy. No offense to the library authors, its just the state of the library - it needs a bit of work. For example, here’s an issue I opened a few days ago when I discovered the swipe deck component crashed when only a single data element was provided: [DeskSwiper throws on single element lists · Issue #562 · GeekyAnts/NativeBase](https://github.com/GeekyAnts/NativeBase/issues/562). The authors fixed it up awfully fast, but, hey, that’s a bug that seems like it could have been caught earlier. 31 | 32 | --- 33 | 34 | ### React Native Elements - [react-native-community/react-native-elements](https://github.com/react-native-community/react-native-elements) 35 | 36 | 37 | This is my personal favorite. The styling is generally platform agnostic; it won’t look out of place using it on either Android or iOS. Each component has simple customization, the docs are solid, and it comes with a good set of icons. This is a no-brainer. 38 | 39 | --- 40 | 41 | ### React Native Material Design - [react-native-material-design/react-native-material-design](https://github.com/react-native-material-design/react-native-material-design) 42 | 43 | 44 | Another solid choice, but mostly only useful for Android. Again, its a bit unsettling to see material design - traditionally a stable of Android devices - on iOS. Besides that, the docs are still a work in progress, as evidenced by the lack of docs for nearly half of the components. Nonetheless, if you’re looking for a material design solution, this is better than nothing. It is also worth noting that the project looks generally unmaintained. 45 | 46 | --- 47 | 48 | ### React Native Material Kit - [xinthink/react-native-material-kit](https://github.com/xinthink/react-native-material-kit) 49 | 50 | Another material design solution, but much better maintained than React Native Material Design. This one has the added benefit of a nicer customization API for creating your own custom components - see the docs on this. It also has some more dynamic components like progress bars and sliders, which you may not see on other frameworks. Anything that helps save you time to build your app is always a solid benefit. 51 | 52 | --- 53 | 54 | ### Do Your Own Styling! 55 | 56 | If none of these choices float your boat, you can always learn how to style components from scratch yourself. I have a course on Udemy that will teach you how to make perfectly reusable components for your own projects. Check it out here: [The Complete React Native and Redux Course - Udemy](https://www.udemy.com/the-complete-react-native-and-redux-course/?couponCode=4IJ2N25F) 57 | -------------------------------------------------------------------------------- /_posts/2014-10-28-twir-a-conference-is-coming.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "TWiR: A Conference is Coming!" 4 | excerpt_separator: 5 | author: Zach Silveira 6 | date: 2014-10-28 13:05 7 | published: true 8 | categories: react 9 | tags: twir 10 | --- 11 | In this second installment of _This Week in React_ we've got some awesome news! [React Conf](http://conf.reactjs.com/) is coming January 28-29. If you're interested in becoming a presenter, you can apply [here](http://conf.reactjs.com/call-for-presenters.html). 12 | 13 | 14 | 15 | ## ReactJS Conf! 16 | 17 | In this second installment of _This Week in React_ we've got some awesome news! [React Conf](http://conf.reactjs.com/) is coming January 28-29. If you're interested in becoming a presenter, you can apply [here](http://conf.reactjs.com/call-for-presenters.html). 18 | 19 | You probably don't care, but I'll be going (along with hopefully the rest of the ReactJSNews team). I plan on blogging throughout the conference, this way you can experience some of the talks if even if you can't make it. The best part is going meeting some of the React community! 20 | 21 | ##What's new this week? 22 | 23 | I always encourage people to tweet me [@ReactJSNews](http://twitter.com/reactjsnews) with any of their creations. It's an easy way to get your stuff out there. 24 | 25 | First up, we've got the [biggest React resource](https://github.com/enaqx/awesome-react) I've ever seen. As of writing this, it's peaked at [#10 on hackernews](https://news.ycombinator.com/item?id=8515192). Check it out if you're looking to learn literally anything dealing with React. Take my word for it, it's probably there. 26 | 27 | ####Components 28 | The first component we've got is a [custom number input field](https://github.com/tleunen/react-number-editor) made by [@Tommy](http://twitter.com/Tommy). It seems to act like a hybrind input / slider field. The component has quite a few options, the example given can be seen here: 29 | 30 | ~~~ 31 | 32 | ~~~ 33 | 34 | You can find all the options [on github](<(https://github.com/tleunen/react-number-editor>). 35 | 36 | [**Domain Driven Forms**](https://github.com/gcanti/tcomb-form) by [@GiulioCanti](https://twitter.com/GiulioCanti) is an awesome library for generating html forms through javascript. Creating a form is just too easy: 37 | 38 | ~~~js 39 | var t = require('tcomb-form'); 40 | 41 | // define a type 42 | var Person = t.struct({ 43 | name: t.Str, 44 | surname: t.Bool 45 | }); 46 | 47 | // create the form 48 | var Form = t.form.createForm(Person); 49 | ~~~ 50 | 51 | Now that for form is created all you need to do is reference it in a React component: `
    `. 52 | 53 | [**React Select**](https://github.com/JedWatson/react-select) is another form based component. I just realized that every component being featured this week deals with forms! That wasn't planned, I swear! Anyways, this component aims to make generating select boxes easier. I like that it makes asynchronously addding options easy. Here's an example with async enabled: 54 | 55 | ~~~js 56 | var getOptions = function(input, callback) { 57 | setTimeout(function() { 58 | callback(null, { 59 | options: [ 60 | { value: 'one', label: 'One' }, 61 | { value: 'two', label: 'Two' } 62 | ], 63 | complete: true 64 | }); 65 | }, 500); 66 | }; 67 | 68 | 142 | ~~~ 143 | 144 | where inputHandler looks something like: 145 | 146 | ~~~js 147 | function(fieldName, event) { 148 | actions.propagateValue({ 149 | field : fieldName, 150 | value : event.target.value 151 | }); 152 | } 153 | ~~~ 154 | 155 | An even better pattern, though, was offered by @insin on the [Hacker News thread](https://news.ycombinator.com/item?id=8811617), noting that instead of placing an onChange handler on every form input, you really only need one handler on the form, like so: 156 | 157 | ~~~ 158 | 159 | ... 160 | 161 | ... 162 |
    163 | ~~~ 164 | 165 | where inputHandler looks like: 166 | 167 | ~~~js 168 | function(event) { 169 | actions.propagateValue({ 170 | field : event.target.name, 171 | value : event.target.value 172 | }); 173 | } 174 | ~~~ 175 | 176 | [Correction: This article had originally said that I thought uncontrolled form fields may be preferable to controlled form fields that are directly controlled by the state. This opinion was mostly unqualified - I now think it advantageous for form fields to correspond to state values and to avoid pointless DOM access.] 177 | 178 | ## Formatting Attributes 179 | 180 | Instead of the long input element above, a cleaner and easier indentation would be: 181 | 182 | ~~~ 183 | 187 | ~~~ 188 | 189 | as opposed to aligning attributes after the tag, 190 | 191 | ~~~ 192 | 195 | ~~~ 196 | 197 | which is still more readable than no indentation, but takes a little more attention than it should. 198 | 199 | ## Closing 200 | 201 | These are a handful of patterns that we've found useful in writing React, and should by no means be considered authoritative at this point. If you have contradicting ideas, please offer them in the comments as this sort of discussion is beneficial for the React ecosystem as a whole. 202 | 203 | I would love to see other style guides emerge to address styling, componentization (including when to use mixins, considerations between props and state, and communication strategies), and Flux. 204 | 205 | Thanks for reading! 206 | -------------------------------------------------------------------------------- /_posts/2016-01-15-bring-your-animations-to-life-with-physics.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Bring your animations to life with physics" 4 | date: 2016-01-14 09:00:09 +1300 5 | excerpt_separator: 6 | author: Thomas Clarkson 7 | published: true 8 | categories: react, angular 9 | --- 10 | 11 | Improve your user's experience with animations. Learn about CSS and Javascript animations and when to use them. 12 | 13 | 14 | 15 | #### Getting started with animations 16 | 17 | To animate is to transition the user interface from one display to another. Animation enhances user experience, providing feeback to user actions and making screens that haven't been introduced before easier to understand. 18 | 19 | An example can be seen with this [React Material UI datepicker](http://www.material-ui.com/#/components/date-picker). 20 | The animations respond to user input and inform the user with transitions that show they are moving back or forward when they change month or select a date. 21 | 22 | ![materialpicker](https://cloud.githubusercontent.com/assets/2054503/12336337/ede568fe-bb68-11e5-8750-7cf50c46a7c7.gif) 23 | 24 | This post will compare using CSS transitions based on time against using spring phsyics to animate transitions. We will use the example of transitioning a box from left to right (You could imagine this being a month view in a calendar that we slide in and out of view). 25 | 26 | 27 | 28 | 29 | #### Example with no Animation 30 | 31 | We will build on this example which doesn't have any animation. Without animation the transition is jarring and doesn't show the user where the item is moving from and to. Look at the code in the Babel tab and see that we use transform: translateX rather than setting the left position because left, top, right, bottom are positioned by the CPU and cause a repaint while items using translate are positioned by the GPU and therefore more performant. 32 | 33 |
       Check out this Pen! 
    34 | 35 | #### Using timed CSS animations 36 | 37 | A CSS transition can be added to the properties of an element with the CSS transition property. Per the [Mozilla docs for transition](https://developer.mozilla.org/en/docs/Web/CSS/transition), we can pass the duration we want the transition to take and a cubic bezier timing function. In this case I have set the duration to 0.5s and used the default timing function of ease. 38 | 39 |
       Check out this Pen! 
    40 | 41 | 42 | #### Cubic Bezier 43 | 44 | ![Cubic Bezier Curve](https://cloud.githubusercontent.com/assets/2054503/12335516/79b72d54-bb64-11e5-8fbe-b2a9e6715ea9.png) 45 | 46 | A cubic bezier curve is a timing function that starts at position 0 and time 0 and ends at 1,1. It accepts four arguments (x1, y1, x2, y2), which are the two control points to determine the shape of the curve. As you can see above, the ease function accelerates at the start and then decelerates at the middle, causing the animation to 'ease' as it finishes. The ease function is just shorthand for cubic-bezier(0.25,0.1,0.25,1). If you want to prove this, re-run this example after changing line 18 to: 47 | 48 | ~~~js 49 | transition: '0.5s cubic-bezier(0.25, 0.1, 0.25, 1)' 50 | ~~~ 51 | 52 | The [cubic bezier site by Lea Verou](http://cubic-bezier.com/) is a great resource for experimenting with different timing functions. Below I have compared a linear function against the ease function. 53 | 54 | ![cubicbeziercom](https://cloud.githubusercontent.com/assets/2054503/12336020/f5c3568c-bb66-11e5-84e8-762a41ba4d58.gif) 55 | 56 | Chrome dev tools allow you to experiment with different curves and also control the speed of animations as seen below. 57 | 58 | ![chromebez](https://cloud.githubusercontent.com/assets/2054503/12336063/4134261e-bb67-11e5-8bbd-4981028659a7.gif) 59 | 60 | #### Why you should use spring physics in animations 61 | 62 | ![damped_spring](https://cloud.githubusercontent.com/assets/2054503/12336758/ff68ac10-bb6a-11e5-9560-15737d665b4d.gif) 63 | 64 | As cubic bezier functions only give you two points of control, it doesn't give the developer enough control to model real life movement. However, by controlling the animation with Javascript, we have full control and can use Hooke's law which expresses how springs extends and contract. Spring animation is already very popular and can be used to provide lively animations in iOS core animation, and in Facebook's Pop and Rebound libraries. 65 | 66 | Look at the cubic bezier animations on the left taken from [framerjs](http://framerjs.com/learn/basics/animation/), compared with the spring animation on the right. The spring animation has a bounce effect - which is not possible with a cubic bezier function. You could acheive this animation with CSS by using key frames, but you would have to hard code the key frame values and duration of the animation. 67 | 68 | ![framer](https://cloud.githubusercontent.com/assets/2054503/12362208/f52638fa-bc26-11e5-895e-59c0ad611928.gif) 69 | 70 | React Motion implements a terse API for you to use spring animation which can be used on the web and with React Native. You have the option to specify the start value (in this case, 0) and the spring physics values you want to animate to. React Motion runs in a request animation frame. The Motion component will keep calling your function to render your animated component with a style object that has the calculated values for each frame. In the example below I have destructured the x property and rendered it in the component. 71 | 72 |
       Check out this Pen! 
    73 | 74 | ##### Continuous fluid interfaces 75 | 76 | In the excellent talk on the [state animation in React](https://www.youtube.com/watch?v=1tavDv5hXpo), Cheng Lou, the creator, highlighted a quote from a former UIKit engineer at Apple. 77 | 78 | 79 | 80 | In the talk, Cheng used an example of animating an opening menu to illustrate this point - "For example, if you have a menu deploy animation that takes 500 milliseconds, and half-way the user clicks on something, and you toggle it back to its initial hidden state, why should this way back also be 500 milliseconds? And also, what should the curve be: ease-in, linear? It is not very clear". 81 | 82 | ![calendardemosmall](https://cloud.githubusercontent.com/assets/2054503/12363885/3f87eebc-bc30-11e5-9ceb-40e2ad34700f.gif) 83 | 84 | The need for a fluid interface is what made me look into react-motion. We are currently building a calendar at [Fergus](http://fergusapp.com/) which requires the ability to respond to drag events and clicks moving the calendar in different directions and by different distances. When we prototyped this with CSS transitions, it was janky and felt slow. 85 | 86 | Compare how fluid the spring motion animation is against the CSS animations by clicking the 'Run animation' button multiple times in quick succession. 87 | 88 |
       Check out this Pen! 
    89 | 90 | #### Configuring React Motion 91 | 92 | The React Motion spring takes two arguments: stiffness and damping (which defaut to 120 and 17, respectively). Four [presets](https://github.com/chenglou/react-motion/blob/master/src/presets.js) are provided: noWobble, gentle, wobbly, and stiff. By adjusting the stiffness and damping below, you can watch how these factors change the animation. 93 | 94 |
       Check out this Pen! 
    95 | 96 | #### When to use CSS Animations 97 | 98 | As Cheng said in his talk, CSS animations are better for animations that you don't want to stop or adjust after they are triggered - such as Twitter's exploding heart animation. This is because CSS animations are more performant. React Motion does incur the cost of having your app re-rendered every animation frame which could be a problem if your application is not performant. 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /_posts/2014-11-06-the-state-of-flux.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "The State of Flux" 4 | excerpt_separator: 5 | author: David Chang 6 | date: 2014-11-06 16:29 7 | published: true 8 | categories: react 9 | --- 10 | Facebook announced Flux at F8 in April as an application paradigm to complement React. But Flux has been pretty nebulous, as there hasn’t been much code released. The examples in Facebook’s Flux repository gave a better idea of its overall composition, but there was still a ton of boilerplate involved, and that’s usually where a library comes along to bring some level of abstraction and convenience. 11 | 12 | 13 | 14 | Facebook announced Flux at F8 in April as an application paradigm to complement React. But Flux has been pretty nebulous, as there hasn’t been much code released. The examples in Facebook’s Flux repository gave a better idea of its overall composition, but there was still a ton of boilerplate involved, and that’s usually where a library comes along to bring some level of abstraction and convenience. 15 | 16 | Assuming a prior knowledge of Flux’s inner workings, here’s a comparison of the following Flux libraries that have been developed by the community: 17 | 18 | - Reflux 19 | - Barracks 20 | - Delorean 21 | - Fluxy 22 | - Fluxxor 23 | - McFly 24 | 25 | ## In keeping with the Action - Dispatcher - Store - View paradigm 26 | 27 | - Reflux merges Actions and the Dispatcher together (so Stores listen to Actions, not dispatched events) 28 | - Barracks basically removes Action Creators, and very tightly couples the Dispatcher and its Stores together (so the View dispatches events directly) 29 | - Delorean keeps all the same, but technically doesn’t have singleton Stores 30 | - Fluxy keeps all the same 31 | - Fluxxor keeps all the same 32 | - McFly keeps all the same 33 | 34 | ## In handling asynchronous requests 35 | 36 | General usage within Flux is straightforward - the one thing that is not exactly intuitive is handling asynchronous requests. This could be considered a Flux design pattern question, but general consensus from engineers at Facebook suggest that asynchronous writes actually do not belong in Stores, but in Action Creators. Asynchronous reads could belong in either. 37 | 38 | I think it is favorable to handle asynchronous requests in actions rather than stores because: 39 | 40 | 1. It is a more consistent pattern to how data flows through the rest of the system 41 | 2. Multiple stores could be interested in listening to the success or failure of a request (such as a generic error handler store), and you typically don’t want to invoke actions from directly within your stores 42 | 43 | That said, here are a variety of different approaches to handling/facilitating asynchronous requests: 44 | 45 | - Reflux does not hinder developers from the above convention in any way - one can simply set up action "listeners," which could invoke the asynchronous request and invoke other actions upon completion. This pattern has been illustrated [here](https://github.com/WRidder/react-spa/blob/master/src/actions/resourceActions.js#L24-L51) or [here](https://gist.github.com/simenbrekken/de69d3ce27ea5934c8b2). Regardless, a solution is not necessarily intuitive as it may be in a library like Fluxy 46 | - Barracks emphasizes the use of waitFor as it actually handles asynchronicity correctly using a concept of middleware chains. This actually seems like it works totally fine for asynchronous writes 47 | - Delorean doesn’t do anything in particular 48 | - Fluxy has a built-in concept of serviceActions that directly facilitates asynchronous requests. A serviceAction will send ${ACTION} upon invocation and subsequently ${ACTION}_COMPLETED or ${ACTION}_FAILED upon completion. Fluxy's dispatcher also has a dispatcher that actually handles waitFor correctly (as opposed to just staggering the order of synchronous calls as Facebook’s Flux Dispatcher or Yahoo’s Dispatchr do), supported with the Bluebird Promises library 49 | - Fluxxor doesn’t do anything in particular (though it contains some good documentation that arrives at the same conclusions as Fluxy) 50 | - McFly may actually inadvertently not allow multiple events to be dispatched asynchronously from a single action (since it seems to expect a synchronous payload object to be returned). So the action factory may actually hinder putting asynchronous requests in actions and force you to handle it in your stores 51 | 52 | ## Added Value 53 | 54 | - Reflux actually offers a ton of convenience methods in unique ways you won’t find in these other libraries. Your stores can listen to other stores and aggregate data across other stores. Creating actions and stores for those actions is particularly easy and can be done without a lot of code. The main impetus for Reflux was that the author didn’t like that stores basically had to compare strings to determine what action had taken place and what it should do, which is very fair. The result is that you don’t have to maintain a list of Constants (or compare strings) everywhere like in the Facebook examples - you basically create actions and you set up listeners on those actions, which honestly makes a lot of sense. A side effect of this is that you don't need to maintain true Constants - multiple stores can essentially have the same API, the same action names, and there is no conflict as there would be with other Flux implementations. 55 | - Barracks boasts a minimal API surface area, which is actually something to behold - there are only 3 functions exposed. But it seems like, in these 3 functions, you can actually get everything you need 56 | - Delorean boasts that it is framework agnostic (React, Flight, Ractive, etc) and it is small (4K gzipped). It really is the only library that doesn’t seem straight up married to React in its demo code 57 | - Fluxy leverages Mori in stores for immutable data structures, so that your components’ shouldComponentUpdate can be ridiculously fast, but that also means you need to use Mori syntax for everything within your stores. It also keeps a history of your store state, so you basically get the ability to undo for free. As mentioned above, the idea of serviceActions basically gives you asynchronous actions for free, without any extra work 58 | - Fluxxor provides convenience create methods for a lot of setup as well as a StoreWatchMixin so that components can listen to Stores without a lot of boilerplate 59 | - McFly provides helper factories to facilitate the creation of actions and stores. It also contains a typical store listener mixin for components 60 | 61 | ## Shortcomings 62 | 63 | - Reflux seems a bit bulletproof at this point - it _does_ stray from the "canonical" Facebook Flux architecture, but it still seems fully featured and, to my attention, there are no legitimate architectural concerns 64 | - Barracks makes a pretty large departure from the canonical Flux architecture by getting rid of action creators and tightly coupling the dispatcher and the stores together. This perhaps comes at the expense of flexibility. If your actions only ever affect one store, there’s no real problem, but if you hypothetically had a single action that should be handled by multiple stores, there’s no good, clean way to handle this (though I wonder how much this happens in the real world). Since Barracks is such a departure from all of these other implementations, if you needed something more conventional later, you’d probably have a hard time migrating and end up having to rewrite/rearchitecture much of your code 65 | - Delorean doesn’t stray much from the “canonical” Facebook Flux architecture - the only thing is that its stores aren’t singletons, but that’s rather nitpicky 66 | - Fluxy doesn’t stray much from the “canonical” Facebook Flux architecture 67 | - Fluxxor doesn’t stray much from the “canonical” Facebook Flux architecture 68 | - McFly’s helper factory to create actions basically makes you return one payload that will be dispatched (from the documentation, it looks like it needs to be synchronous) 69 | 70 | ## Takeaways 71 | 72 | If you want to stick to Flux as purely as possible, use Fluxxor, Delorean, or McFly. 73 | 74 | If you want convenience and novelty, Reflux and Fluxy will give you a pretty fun experience. 75 | 76 | If you are feeling rebellious or want a truly minimal surface area, go with Barracks. 77 | 78 | ## Corrections 79 | 80 | 7/17/14: Corrections to Reflux 81 | 82 | - Handling asynchronous requests had read: "Reflux’s design doesn’t exactly fit with the above paradigm, since an asynchronous read or write can’t be run from an action. It would have to be run from a Store - if other Stores were interested in whether the action succeeded or failed, you would either have to invoke follow up actions from within the Store or make interested Stores listen to changes in that Store, since that’s also a unique capability of Reflux." 83 | - Shortcomings had read: "Reflux has a listenTo component mixin to listen to changes in your store, but you still have to do more work than other libraries - you still have to set up both onChange and onInit methods that I’d expect to be equivalent and could be abstracted away if you enforced the presence of a function like getStoreData in either the component or the Store." Actually, Reflux provides a connect method that removes your need for onChange in general cases. You still may need to declare your initial state. 84 | - Shortcomings had also read: "As aforementioned, Reflux also does not have a straightforward solution to handling asynchronous requests" which was not true and was fixed under the "Handling Asynchronous Requests" section 85 | -------------------------------------------------------------------------------- /_posts/2015-08-06-composing-components.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "React.Component vs React.createClass" 4 | excerpt_separator: 5 | author: Naman Goel & Zach Silveira 6 | date: 2015-08-06 21:35 7 | published: true 8 | categories: react 9 | --- 10 | 11 | React has supported building components two different ways for a few months. You can extend from `React.Component` or use `React.createClass` which has been available since the beginning of React. Is there a good reason to use one over the other? 12 | 13 | 14 | 15 | React has supported building components two different ways for a few months. You can extend from `React.Component` or use `React.createClass` which has been available since the beginning of React. Is there a good reason to use one over the other? 16 | 17 | Maybe, maybe not. That's up to you. Big names in the React community generally lean the same way: 18 | 19 | 20 | 21 | 22 | 23 | There's also those of us who are more neutral on the subject: 24 | 25 | 26 | 27 | 28 | 29 | Here’s my take: In the large scheme of things, it doesn’t matter that much. For most of the cases out there, the difference between `React.createClass` and `class X extends React.component` is that of syntax. If you don’t use mixins or decorators often, just choose the syntax you like the best. 30 | 31 | But apart from that, there are some real reasons to choose one way over the other. 32 | 33 | There are some real features you lose by going with ES6 Classes (I’m not going to say ES2015, you can’t make me!) — namely mixins, autoBound functions and the oft-forgotten this.isMounted method. ES6 classes also means you now have a hard dependency on a tool like Babel. If you’ve not embraced JSX, and are currently writing ES5 code that doesn’t need transpilation, this might be a dealbreaker for you. 34 | 35 | But before we get into the pros and cons list, let say something that people tend to overlook. Using ES6 classes instead of React.createClass DOES NOT make your code any more or less Object oriented. It’s just a different syntax for defining classes folks, it has a fewer features, but essentially you’re moving from a factory pattern to a constructor pattern. So, if you like your code nice and functional, this should be a non-debate for you. 36 | 37 | On the flip side, using ES6 classes does make it easier to do inheritance. But please, don’t. Let me put it this way, if you’re going to use ES6 classes just so you can make deep inheritance chains, just stick to React.createClass and write some mixins. 38 | 39 | ## Reasons to use React.createClass 40 | 41 | ### "I like auto-binding functions" 42 | 43 | This is a valid argument, except you **can** autobind with ES2015 classes, (See the [React blog post](https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding)) 44 | 45 | Using Babel stage: 0 (which I’m personally a huge fan of) you can write your classes like this: 46 | 47 | ~~~js 48 | class Counter extends React.Component { 49 | tick = () => { 50 | ... 51 | } 52 | ... 53 | } 54 | 55 | ~~~ 56 | 57 | If you think stage: 0 is way too extreme, there are other options out there. You can, for example, use an [autobind decorator](https://github.com/andreypopp/autobind-decorator): 58 | 59 | But decorators are a stage: 0 feature, I hear you say. Yes, but you don’t need stage: 0: 60 | 61 | ~~~js 62 | class Counter extends React.Component { 63 | tick() { 64 | ... 65 | } 66 | render(){ 67 | ... 68 | } 69 | ... 70 | } 71 | 72 | export default autobind(Counter) 73 | ~~~ 74 | 75 | ### "I like mixins” 76 | 77 | This is pretty much the main reason people are sticking to React.createClass, and for good reason. There are large React code bases that rely on mixins. React-router, for example, gets a lot of power by using mixins. 78 | Again, you can use [React-mixin](https://www.npmjs.com/package/react-mixin), to use mixins with ES6 classes, but you may be getting annoyed by the decorators by now. 79 | 80 | ### Little things like this.isMounted 81 | 82 | You hardly ever need to use them, and when you do, they are easy to add. Personally I find no reason for using `this.isMounted` in your code. 83 | 84 | ## Reasons to switch to the ES6 syntax 85 | 86 | ### Autobinding? 87 | Maybe this is stockholme syndrome, but we’ve been dealing with context issues in Javascript so long, that it’s starting to feel right. The automatic autobinding that React.createClass handles for you can be confusing to beginners, and the implicit nature of the binding can be confusing even after months for some. 88 | ES6 classes make you explicitly bind your methods. Which makes everything clearer, and will help developers new to React grok what’s going on. With some of the latest Babel-supported ES6/7 features, manual binding isn't much of a problem. 89 | 90 | ### Move over Mixins, use Higher-Order-Components 91 | Go to any conversation about ES6 classes, and you’ll find someone telling you to use composition over inheritance. You may have seen this meme before: 92 | 93 | ![Compose all the things](https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRW8W5l3CTR2UAHMvtdvCT-hyJc3Od5gJnyXyS6qrQQDXWLPevMkr164v_S) 94 | 95 | The fact is that inheritance is a terrible way to code. It’s error-prone, clunky and hard to understand. It can lead to extremely brittle code, and forces you to write all your code the same way. Mixins are definitely a much better solution, but developers still tend to abuse them to do things that could simply be done with composition. Who said you can’t be functional with classes? As an added bonus, Higher-Order-Component will work with both kinds of classes, and will be forward compatible with pure functions. 96 | 97 | On the other hand, using decorator functions, you can do some very powerful things with ES6 classes, such as polyfill the oft-discussed polyfill API. This power should be used sparingly, but when you do need it, it’s nice to have. 98 | 99 | ### No Cruft 100 | Getting rid of features such as this.isMounted which is rarely used in practice helps React be lighter and more nimble. Over time this is also helping React be faster. I know we all love React, but we also want to keep winning the speed tests, don’t we. 101 | 102 | ### FlowTypes 103 | This is one is near and dear to my heart. For a very long time, I’ve pretty much ignored Typescript and Flow, but after losing a whole day to a typo in an event name, I started using flow in my code and I haven’t looked back. Flow lets you embrace it slowly on a file-by-file basis, and even though it may make you jump through hoops sometimes to work around errors, it will find a whole bunch of subtle errors that you didn’t even know existed. 104 | 105 | But what does this have anything to do with ES6 class syntax? Flowtype (and typescript) are much easier to use if you’re using ES6 classes. 106 | 107 | This is how you can annotate properties in an ES6 class: 108 | 109 | ~~~js 110 | Class X extends React.Component { 111 | someProp: string | number; 112 | state: SomeType; 113 | props: SomeType; 114 | ... 115 | } 116 | ~~~ 117 | 118 | The same is a little more complicated with React.createClass 119 | ~~~js 120 | React.createClass({ 121 | someProp: (0: string | number), 122 | ... 123 | }) 124 | ~~~ 125 | 126 | You can’t even define types for props and state with flow with React.createClass. Instead, flow depends on a huge amount of custom code to figure out the types for props by looking at propTypes. In practice, it never works that well. And type checking state is simply not even possible. 127 | 128 | ##Conclusion 129 | 130 | Neither of these options for creating your classes are going away anytime soon. I feel that things are headed towards the ES6 way of doing things but it will be a while until it's mainstream. If it ever becomes something everyone chooses over `createClass`, Javascript needs more than just syntactic sugar, it needs real classes. I choose to write my components the ES6 way mainly because I feel that it looks a little nicer, no commas after every function and the downsides to using this syntax doesn't bother me that much. We would love to hear feedback in the comments about what you think! Hopefully we'll discuss this on the next episode of the [React Podcast](http://reactpodcast.com). 131 | -------------------------------------------------------------------------------- /_posts/2015-12-01-building-a-react-based-application.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Building a React-based Application" 4 | excerpt_separator: 5 | author: Marc Scholten 6 | date: 2015-12-01 17:15 7 | published: true 8 | categories: react 9 | --- 10 | 11 | Building a frontend application is hard. Compared to building backend applications, you have way too much mutable state to manage and in the end your whole code base is so complex that nobody wants to touch anything. 12 | 13 | We already know how to build backend applications - generating html, sending it to the browser, repeat - without it ending in a nightmare of complexity, but building frontend stuff is very complicated. Backend is easy, frontend is hard. So, why don't we just build the frontend like the backend? 14 | 15 | 16 | 17 | Building a frontend application is hard. Compared to building backend applications, you have way too much mutable state to manage and in the end your whole code base is so complex that nobody wants to touch anything. 18 | 19 | We already know how to build backend applications - generating html, sending it to the browser, repeat - without it ending in a nightmare of complexity, but building frontend stuff is very complicated. Backend is easy, frontend is hard. So, why don't we just build the frontend like the backend? 20 | 21 | ## Building it like a backend application 22 | 23 | A good old web application usually consists of a router mapping the current url to a controller action which will render the whole page including the outer layout. The big picture looks like this: 24 | 25 | ![](http://mpscholten.github.io/assets/good-old-web-application.png) 26 | 27 | By replicating this cycle in our frontend application we can - together with react - reach an easier to understand application design with less mutable parts. 28 | 29 | ## Implementing it 30 | When the user is navigating to a different view, we will just use links. When the user clicks a link an event handler will tell the router to render the new page (by using `window.history.pushState`). Our frontend application flow now looks like this: 31 | 32 | ![](http://mpscholten.github.io/assets/great-new-react-application.png) 33 | 34 | This leads to a one-directional data flow which is easier to reason about than a bidirectional data flow which you can usually find in frontend applications. 35 | 36 | Let's take a look to some example code. 37 | 38 | 39 | ## The Application Component 40 | 41 | ```js 42 | // Application.jsx 43 | import Router from "./Router" 44 | import { routes as postRoutes } from "./PostView" 45 | import { routes as accountRoutes } from "./AccountView" 46 | 47 | class Application { 48 | render() { 49 | if (this.state.user) { 50 | return 51 | } else { 52 | // not logged in 53 | return 54 | } 55 | } 56 | 57 | _routes() { 58 | // merge the routes of all the modules 59 | return [].concat(postRoutes(this.state.user), accountRoutes(this.state.user)) 60 | } 61 | 62 | componentDidMount() { 63 | let oldPushState = window.history.pushState 64 | 65 | window.history.pushState = (state, title, url) => { 66 | this.setState({url: url, user: state}) 67 | 68 | oldPushState.call(window.history, state, title, url) 69 | }; 70 | window.onpopstate = (event) => { 71 | this.setState({url: window.location.pathname}) 72 | }; 73 | 74 | // after initial page load use the current url to kick off the app 75 | this.setState({url: window.location.pathname}) 76 | } 77 | } 78 | 79 | // Router.jsx 80 | export default class Router { 81 | render() { 82 | // find matching regular expression 83 | let routeIndex = routes.findIndex(route => { 84 | let regularExpression = route[0]; 85 | return this.props.url.match(regularExpression) !== null; 86 | }); 87 | 88 | if (routeIndex === -1) { 89 | throw new Error(`${this.props.url} not found`) 90 | } else { 91 | let matches = this.props.url.matches(routes[routeIndex][0]) 92 | // call route handler with regex matches 93 | return routes[routeIndex][1].apply(this, matches.slice(1)) 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | We have an `Application` component which will intercept `window.history.pushState` calls to rerender the page when the url changes. The `Application` also keeps a user as it's state. The user is just a plain old javascript object[[0]](#note-0). If the user has some relations (e.g. the user has some blog posts) these relations will be part of the user object, so that you only have one single application data state. So the major mutable parts of the whole application are capsulated in the `Application`. 100 | 101 | Once the user has logged in `Application.state.user` will be set by calling `window.history.pushState(user, undefined, undefined)` from the login view. [Remember: The first argument of `pushState` can be any javascript object](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState). 102 | 103 | If a view is updating the user (e.g. account settings) it will not mutate the user object, instead it will create a copy and update the copy. Then it will use `window.history.pushState(newUser, undefined, undefined)` to push the updated user object to the `Application`[[1]](#note-1). The views always have the latest user object by design, the views cannot get out of sync with the data. Also there is no mutable data, awesome! 104 | 105 | The user object is passed down from the `Application` to the views by [currying](https://en.wikipedia.org/wiki/Currying) the route actions (`postAction` in the code below) with the user. 106 | 107 | 108 | ## The Link Component 109 | 110 | ```js 111 | // Link.jsx 112 | class Link { 113 | render() { 114 | {this.props.children} 115 | } 116 | 117 | _handleClick(event) { 118 | event.preventDefault() 119 | window.history.pushState({}, null, this.props.to) 120 | } 121 | } 122 | ``` 123 | 124 | A `Link` component will render good old `..` elements, but will intercept the `onClick` event to use `window.history.pushState` instead of doing a real http request. 125 | 126 | 127 | ## The Views 128 | 129 | ```js 130 | // PostView.jsx 131 | import { accountUrl } from "./AccountView" 132 | class PostView extends { 133 | render() { 134 | return 135 |

    {this.props.title}

    136 |
    {this.props.body}
    137 | View my account 138 |
    139 | } 140 | } 141 | 142 | function postAction(user) { 143 | return postId => 144 | } 145 | 146 | export const routes = user => [ 147 | [new Regex('^/posts/(\d+)$'), postAction(user)] 148 | ] 149 | 150 | // AccountView.jsx 151 | export const accountUrl = user => 152 | `/my-account` 153 | 154 | ``` 155 | 156 | You can see that the view modules only export their routes and their url generator functions. So communication across views only happens via `Links` or more specifically by routing. 157 | 158 | It's the views responsibility to display the full page including an outer layout. This is just like a view in [rails](https://github.com/railstutorial/sample_app_rails_4/blob/master/app/views/users/show.html.erb) or [symfony](https://github.com/symfony/symfony-demo/blob/master/app/Resources/views/default/homepage.html.twig). The best way to do this is by introducing an `OuterLayout` component. 159 | 160 | ## Why not flux 161 | 162 | Flux is IMO a great pattern for building hybrid react apps (so not using react everywhere). In case you’re using a pure react based application you don’t need data stores and dispatchers. Data stores and dispatchers lead to mutable state and indirect code. Having multiple data stores also introduces multiple sources of truth, which increases complexity. If your app is only using react for some parts flux is a great solution, but if you are using react for everything you are better of with direct code and immutable data. 163 | 164 | 165 | ## Takeaways 166 | 167 | By building your react application like a backend application - introducing clearly seperated views, communicating only via urls - you will archieve a simple single directed data flow. By using immutable data structures the only major state (so, ignoring ui state like animation state) is a tuple of the user data structure and the current url. 168 | 169 | Thanks for reading :) If you have any suggestions [let me know](mailto:marcphilipscholten@gmail.com)! 170 | 171 | [Check out my personal blog](http://www.mpscholten.de/) if you're interested in more of this stuff! 172 | 173 |
    174 |
    175 | [0] An example user object could look like this: 176 | 177 | ```{ id: 1, email: 'hello@example.com', posts: [{title: 'My first post', content: 'Lorem ipsum'}] }```. 178 | 179 |
    180 |
    181 | [1] Usually you do this after sending an ajax request to the server. With promises this could look like this: 182 | 183 | ```js 184 | // The user has changed his email via the AccountView 185 | updateEmail(newEmail) 186 | .then(() => { 187 | let newUser = Object.assign({}, this.props.user, {email: newEmail}) 188 | window.history.pushState(newUser, undefined, undefined) 189 | }) 190 | .catch(error => ...) 191 | ``` 192 | 193 | where `updateEmail` is doing an ajax request and returning a [Promise](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise). 194 | -------------------------------------------------------------------------------- /_posts/2016-03-13-webpack-in-production.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "React Router & Webpack in Production" 4 | date: 2016-03-13 17:00:09 +1300 5 | excerpt_separator: 6 | author: Zach Silveira 7 | published: true 8 | categories: react, webpack 9 | --- 10 | 11 | I've been working on a pretty large [react-router](https://github.com/reactjs/react-router) codebase at work. Currently it has around 50~ code splits, which as you can imagine, is a lot of routes. This is going to be a post on the things I've learned throughout building out my development / production config and how we are using webpack in production. 12 | 13 | 14 | 15 | ###Initial Setup 16 | 17 | Before I really dive into how my webpack config is setup and the problems I've found, I'll quickly go over how this app is setup. Currently, there's one entry point and it looks like this: 18 | 19 | ```js 20 | import React from 'react' 21 | import { render } from 'react-dom' 22 | import { match, Router, browserHistory } from 'react-router' 23 | import AsyncProps from 'async-props' 24 | import routes from '../routes/index' 25 | /* globals document, window */ 26 | 27 | const { pathname, search, hash } = window.location 28 | const location = `${pathname}${search}${hash}` 29 | 30 | match({ routes, location }, () => { 31 | render( 32 | } 34 | routes={routes} 35 | history={browserHistory} 36 | />, 37 | document.getElementById('app') 38 | ) 39 | }) 40 | 41 | ``` 42 | 43 | It looks like a standard react-router setup, except a couple things are different. For one, there's way too many routes to have them all in this file, so we are importing the main route object into this file. Second, we are using `match` on the client side. Without matching first, the client side would try to render before the splits were downloaded causing an error. You can read a little more about match on the client [here](https://github.com/reactjs/react-router/issues/1990#issuecomment-141350392). 44 | 45 | Next, we are using Ryan Florence's awesome [async-props](https://github.com/ryanflorence/async-props) library for loading data into components. It allows me to load data from an api before the server renders components. It will pass the data down to the client for the client-side render, and then data will load as you navigate to new pages automatically. 46 | 47 | ###Routes 48 | 49 | Our main routes file looks like this: 50 | 51 | ```js 52 | 53 | export default { 54 | component: 'div', 55 | path: '/', 56 | indexRoute: require('./index'), 57 | childRoutes: [ 58 | require('./login'), 59 | require('./account'), 60 | ... 61 | ] 62 | } 63 | ``` 64 | 65 | There's a lot more require's in our app of course. And these are nested pretty deep. The files referenced in the root file have more child routes, and those use 66 | `require.ensure` which you can read about in the webpack docs on [code splitting](https://webpack.github.io/docs/code-splitting.html). It tells webpack to make a new bundle, and then load that bundle when require.ensure is called on the client. Here's an example: 67 | 68 | ```js 69 | if(typeof require.ensure !== "function") require.ensure = function(d, c) { c(require) } 70 | 71 | module.exports = { 72 | path: 'account', 73 | getComponent(location, cb) { 74 | require.ensure([], (require) => { 75 | cb(null, require('../../views/master/index.jsx')) 76 | }) 77 | }, 78 | childRoutes: [ 79 | require('./settings'), 80 | ] 81 | } 82 | ``` 83 | 84 | There's a few things going on here. First, we have a function at the top that will polyfill `require.ensure`. Why? Well, on this project we are server rendering our whole site as well, which I would rather not do, but due to the type of site we are building: we have to. The next thing is the relative require path. I'm using this awesome [babel resolver plugin](https://github.com/jshanson7/babel-plugin-resolver) along with webpack's [resolve paths](https://webpack.github.io/docs/configuration.html#resolve) so that I can import files like this: 85 | 86 | ```js 87 | import Header from '../../master/header' 88 | //becomes 89 | import Header from 'master/header' 90 | 91 | ``` 92 | 93 | Why do I have to use a babel plugin AND webpack's resolve feature? Once again, doing a server rendered app, the code is ran on the server and also through webpack. In this particular app, I haven't had time to experiment with [webpacking the server](https://github.com/webpack/react-webpack-server-side-example). Anyways, if I didn't use the babel plugin, errors would be thrown on the server, but webpack would work fine. This is one of the common things I have ran into while building this app. 94 | 95 | Realizing some things need to be done slightly different on the server or client. You may still be wondering why I am referencing the component as a relative path in the above route example, and that's because the babel plugin I'm using only works with `import` and not `require`. My route objects are the one place that I have these "nasty" looking paths. 96 | 97 | ##Webpack 98 | 99 | I was prompted to make this article after tweeting this out: 100 | 101 | 102 | 103 | 104 | A couple people wanted a better explanation as to what's happening here. When I was first building my production webpack config, even after using all of these plugins: 105 | 106 | ```js 107 | new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'), 108 | new webpack.optimize.OccurenceOrderPlugin(), 109 | new webpack.optimize.DedupePlugin(), 110 | new webpack.optimize.UglifyJsPlugin({ 111 | compress: { warnings: false }, 112 | comments: false, 113 | sourceMap: false, 114 | mangle: true, 115 | minimize: true 116 | }), 117 | 118 | ``` 119 | 120 | My bundle looked like this: 121 | 122 | ![Webpack Output](https://reactjsnews.com/img/webpack-production/before.png) 123 | 124 | That's pretty huge if you think about it. And I'm not talking about the amount of bundles. I'm talking about the file size. After searching everywhere for a solution to get the bundle size down further, I found webpack's [AggressiveMergingPlugin](https://webpack.github.io/docs/list-of-plugins.html#aggressivemergingplugin). This thing is a life saver. As you may have seen from the tweet, the output turns into this: 125 | 126 | ![Webpack Output](https://reactjsnews.com/img/webpack-production/after.png) 127 | 128 | Just having the main, vendor, and one other bundle brings the whole site under 1MB. I'm using the plugin to only merge files if the size reduction is more than 50%, which is the default. 129 | 130 | People talk about code splitting in webpack and think it's really amazing to load the JS for the page you're on and nothing more. It sounds great. The problem is that the file size is immensely bigger. If someone more familiar with webpack has a better idea as to why this is, I'd like a better explanation. It isn't feasable to keep the splits instead of merging them. This site is pretty large, with a lot of routes as you can tell from the screenshots. Codesplitting without merging would cause way more waiting on the client side every time you navigate to a new page. Even if the JS was heavily cached, the first time you hit these pages it will have to load a 300kb bundle for some of them. 131 | 132 | ##Caching 133 | 134 | That takes us to caching. We are about a month away from publicly launching this site, so we haven't setup the workflow for pushing updates through a cdn, but that will be the end result. For now, in my webpack config, my output object looks like this: 135 | 136 | ```js 137 | output: { 138 | path: __dirname + '/public/assets/js/[hash]/', 139 | filename: '[name].js', 140 | chunkFilename: '[id].js', 141 | publicPath: '/assets/js/[hash]/' 142 | }, 143 | ``` 144 | 145 | This is in the production config of course. This way I can cache the files and when I update the code, the hash will change and the browser won't be caching the old code. I pass in the hash as an env variable at runtime to that the server has the correct path to the assets folder. 146 | 147 | 148 | ##Problems 149 | 150 | There were a few big problems I came across while building out a server rendered app with dynamic routes. The first was page titles. How am I supposed to have the right title on the client and on the initial server render? Thankfully, Ryan has yet another solution. [react-title-component](https://github.com/ryanflorence/react-title-component) solves this perfectly. 151 | 152 | The next was, how do I hit an api, wait for the response on server render, load new data on route changes, and of course, do this at the component level. As I mentioned before, [async-props](https://github.com/ryanflorence/async-props) solves this problem too. It will give you route info so that you can make requests based on things in the url. 153 | 154 | The next problem is one that I haven't fully solved. Webpack is getting really slow. It takes around 20 seconds on a maxed out macbook 15" to build code in production. On the server, it takes more like a minute! If I'm in development mode, it takes around 10 seconds to make the initial build, and sometimes it lags on building the splits on code change. If anyone has insight into this I would love to hear it. 155 | 156 | This one goes along with the webpack one, and it is reloading the server. I haven't tried to webpack the server but I hear doing so works great for this. I don't think it would fix the problem with webpack being slow though, and in fact it would probably make it even slower. 157 | 158 | 159 | ##Folder structure 160 | 161 | I almost forgot to throw this one in here! I'm really happy with the structure of this project. I have a views folder that has all of the same folders and file names as the routes folder. It makes it really easy to find things. These also correspond with the URL to the page. `/account/settings` will be in `views/account/settings.jsx` and `routes/account/settings.js`. The same is true for my tests folder. 162 | 163 | 164 | ##Conclusion 165 | 166 | I hope this gave you a good glimpse at how webpack and react router work at a larger scale than you see most blog posts cover. If you have any questions or things that you would like me to talk about that I haven't already, please leave a comment below and I will update this post! I'm sure that I forgot a few problems and tips writing this. I was thinking this would be a short post but it blew up on me! 167 | -------------------------------------------------------------------------------- /_sass/_main.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | Pixyll 4 | A simple, beautiful theme for Jekyll that emphasizes content rather than 5 | aesthetic fluff. 6 | Best served with BASSCSS (http://jxnblk.github.io/basscss) 7 | Crafted with <3 by John Otander (@4lpine) - ©2015 John Otander 8 | MIT License http://opensource.org/licenses/MIT 9 | */ 10 | #carbonads, .carbon-wrap{ 11 | display: -webkit-flex; 12 | display: -ms-flexbox; 13 | display: flex; 14 | -webkit-align-items: center; 15 | -ms-flex-align: center; 16 | align-items: center; 17 | -webkit-justify-content: center; 18 | -ms-flex-pack: center; 19 | justify-content: center; 20 | } 21 | 22 | .carbon-img{ 23 | min-width: 150px; 24 | } 25 | 26 | .carbon-text{ 27 | font-size: 15px; 28 | padding: 5px; 29 | } 30 | 31 | .carbon-poweredby{ 32 | font-size: 10px; 33 | float: right; 34 | } 35 | 36 | body { 37 | font-family: "Merriweather", "PT Serif", Georgia, "Times New Roman", serif; 38 | } 39 | 40 | html, body { 41 | height: 100%; 42 | } 43 | 44 | img { 45 | width: auto; 46 | max-width: 100%; 47 | } 48 | 49 | .site-wrap { 50 | min-height: 100%; 51 | margin-bottom: -120px; 52 | } 53 | 54 | .site-wrap:after { 55 | content: ""; 56 | display: block; 57 | } 58 | 59 | .footer, .site-wrap:after { 60 | height: 120px; 61 | } 62 | 63 | body { 64 | font-size: 1.5rem; 65 | 66 | box-sizing: border-box; 67 | -moz-box-sizing: border-box; 68 | -webkit-box-sizing: border-box; 69 | } 70 | 71 | .gist, 72 | .gist .highlight .p { 73 | font-size: .75rem; 74 | } 75 | 76 | .gist .lines { 77 | width: 100%; 78 | } 79 | 80 | .site-header a { 81 | color: #333; 82 | font-weight: 300; 83 | } 84 | 85 | .site-header nav a { 86 | font-size: 1rem; 87 | color: #666; 88 | } 89 | 90 | .site-header nav a:hover { 91 | color: #444; 92 | opacity: 1; 93 | border-bottom: 2px solid #444; 94 | } 95 | 96 | .site-nav a + a { 97 | margin-left: 1em; 98 | } 99 | 100 | .site-nav { 101 | margin: 0; 102 | padding: 0; 103 | } 104 | 105 | .site-header a:hover, 106 | .posts .post a:hover .post-meta, 107 | .posts .post a:hover .post-title, 108 | .posts .post a:hover .post-summary { 109 | opacity: 0.88; 110 | } 111 | 112 | /* 113 | Table styles copied from Bootstrap 114 | Copyright (c) 2013 Twitter, Inc 115 | */ 116 | 117 | table { 118 | width: 100%; 119 | max-width: 100%; 120 | margin-bottom: 1.5; 121 | font-size: 1.125rem; 122 | // Cells 123 | > thead, 124 | > tbody, 125 | > tfoot { 126 | > tr { 127 | > th, 128 | > td { 129 | padding: 12px; 130 | line-height: 1.2; 131 | vertical-align: top; 132 | border-top: 1px solid #333; 133 | } 134 | } 135 | } 136 | // Bottom align for column headings 137 | > thead > tr > th { 138 | vertical-align: bottom; 139 | border-bottom: 2px solid #333; 140 | } 141 | // Remove top border from thead by default 142 | > caption + thead, 143 | > colgroup + thead, 144 | > thead:first-child { 145 | > tr:first-child { 146 | > th, 147 | > td { 148 | border-top: 0; 149 | } 150 | } 151 | } 152 | // Account for multiple tbody instances 153 | > tbody + tbody { 154 | border-top: 2px solid #333; 155 | } 156 | } 157 | 158 | .related-post-title { 159 | border-bottom: thin solid #f3f3f3; 160 | } 161 | 162 | .posts { 163 | margin: 0; 164 | } 165 | 166 | .posts .post { 167 | margin-bottom: 0.75em; 168 | padding-bottom: .375em; 169 | border-bottom: thin solid #f3f3f3; 170 | } 171 | 172 | .posts .post:last-child { 173 | border-bottom: none; 174 | margin-bottom: .375em; 175 | padding-bottom: 0; 176 | } 177 | 178 | .post-link .post-title { 179 | margin-top: 0; 180 | font-weight: 600; 181 | color: #333; 182 | } 183 | 184 | .post-footer { 185 | @extend .italic; 186 | 187 | margin-top: .75rem; 188 | text-align: center; 189 | } 190 | 191 | .post-footer .avatar { 192 | margin: 2rem 0; 193 | width: 100px; 194 | border-radius: 50%; 195 | } 196 | 197 | .pagination, 198 | .button { 199 | font-size: 1rem; 200 | font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; 201 | font-weight: 300; 202 | text-align: center; 203 | } 204 | 205 | .pagination a, .pagination .disabled { 206 | transition: all 0.2s ease-in-out; 207 | background: #fafafa; 208 | border-radius: 0.1875em; 209 | border: 1px solid #f3f3f3; 210 | color: #333333; 211 | padding: 1em 1.5em; 212 | } 213 | 214 | .pagination .disabled { 215 | opacity: 0.5; 216 | } 217 | 218 | .pagination a:hover, .pagination a:focus { 219 | background: white; 220 | color: #477dca; 221 | } 222 | 223 | .pagination a:active { 224 | background: #f7f7f7; 225 | } 226 | 227 | .wrap .measure { 228 | margin: 0 auto; 229 | } 230 | 231 | .meta, 232 | .post-meta { 233 | width: auto; 234 | font-size: 1rem; 235 | font-weight: 300; 236 | margin: 0; 237 | padding: .25em 0; 238 | color: #7a7a7a; 239 | font-style: italic; 240 | } 241 | 242 | .pagination .button { 243 | font-size: 1rem; 244 | font-weight: 300; 245 | letter-spacing: 1px; 246 | } 247 | 248 | .button-disabled { 249 | opacity: 0.55; 250 | background-color: #999; 251 | } 252 | 253 | .button-disabled:hover, 254 | .button-disabled:active, 255 | .button-disabled:focus { 256 | cursor: not-allowed; 257 | background-color: #999; 258 | } 259 | 260 | form { 261 | font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; 262 | font-weight: 300; 263 | font-size: 1rem; 264 | } 265 | 266 | textarea.input { 267 | height: 8em; 268 | } 269 | 270 | p { 271 | font-weight: 300; 272 | line-height: 1.5; 273 | color: #333; 274 | } 275 | 276 | abbr { 277 | border-bottom: 1px black dotted; 278 | cursor: help; 279 | } 280 | 281 | pre, code { 282 | font-family: Menlo, Monaco, "Courier New", monospace 283 | } 284 | 285 | code { 286 | color: #7a7a7a; 287 | } 288 | 289 | pre { 290 | padding: 1.125em; 291 | font-size: 1.125rem; 292 | line-height: 1.11; 293 | overflow-x: scroll; 294 | margin-bottom: 0.88em; 295 | } 296 | 297 | .highlight .p { 298 | font-size: 1.125rem; 299 | line-height: 1; 300 | } 301 | 302 | blockquote { 303 | padding: 1.33em; 304 | font-style: italic; 305 | border-left: 5px solid #7a7a7a; 306 | } 307 | 308 | blockquote footer { 309 | font-size: .85rem; 310 | font-style: normal; 311 | background-color: #fff; 312 | color: #7a7a7a; 313 | border-color: transparent; 314 | } 315 | 316 | h1, 317 | .h1, 318 | h2, 319 | .h2, 320 | h3, 321 | .h3, 322 | h4, 323 | .h4, 324 | h5, 325 | .h5, 326 | h6, 327 | .h6 { 328 | font-family: "Lato", 'Helvetica Neue', Helvetica, sans-serif; 329 | font-weight: 900; 330 | line-height: 1.2; 331 | margin: 1em 0 0.5em; 332 | } 333 | 334 | .social-icons { 335 | padding: 0.5em 0 0 0; 336 | font-size: 1.25rem; 337 | width: 100%; 338 | } 339 | .social-icons a.fa { 340 | padding: 0.2em; 341 | opacity: 0.8; 342 | cursor: pointer; 343 | } 344 | .social-icons a.fa:hover { 345 | opacity: 1; 346 | } 347 | .social-icons iframe[title=Flattr] { 348 | position: relative; 349 | top: 0.1em; 350 | } 351 | 352 | @media screen and (min-width: 48em) { 353 | .site-header .site-title { 354 | float: left; 355 | } 356 | 357 | .meta, 358 | .post-meta { 359 | margin: 0; 360 | padding: 0; 361 | font-size: 1.25rem; 362 | } 363 | 364 | .h1, 365 | h1 { 366 | font-size: 3.250rem; 367 | } 368 | 369 | .h2, 370 | h2 { 371 | font-size: 2.298rem; 372 | } 373 | 374 | .h3, 375 | h3 { 376 | font-size: 1.625rem; 377 | } 378 | 379 | .h4, 380 | h4 { 381 | font-size: 1.150rem; 382 | } 383 | 384 | .p, 385 | p, 386 | li { 387 | font-size: 1.25rem; 388 | line-height: 1.8; 389 | } 390 | 391 | .small { 392 | font-size: 1rem; 393 | } 394 | 395 | table { 396 | font-size: 1.25rem; 397 | } 398 | 399 | .post-link .post-title { 400 | margin-top: 0.5em; 401 | } 402 | 403 | .posts .post { 404 | margin-bottom: 1.333em; 405 | padding-bottom: 0.666em; 406 | border-bottom: thin solid #f3f3f3; 407 | } 408 | 409 | .posts .post:last-child { 410 | border-bottom: none; 411 | margin-bottom: .333em; 412 | padding-bottom: 0; 413 | } 414 | } 415 | 416 | @media screen and (max-width: 48em) { 417 | blockquote { 418 | margin-left: 1rem; 419 | margin-right: 0; 420 | padding: 0.5em; 421 | } 422 | 423 | .h1, 424 | h1 { 425 | font-size: 2.827rem; 426 | } 427 | 428 | .h2, 429 | h2 { 430 | font-size: 1.999rem; 431 | } 432 | 433 | .h3, 434 | h3 { 435 | font-size: 1.413rem; 436 | } 437 | 438 | .h4, 439 | h4 { 440 | font-size: 1rem; 441 | } 442 | 443 | .site-header { 444 | text-align: center; 445 | } 446 | 447 | .site-header .site-title { 448 | float: center; 449 | } 450 | 451 | .site-header .site-nav { 452 | width: 100%; 453 | float: left; 454 | text-align: center; 455 | margin-top: 0.666em; 456 | margin-bottom: 1.333em; 457 | } 458 | 459 | .social-icons .left, .social-icons .right { 460 | text-align: center; 461 | float: none; 462 | } 463 | } 464 | 465 | @media screen and (min-width: 64em) { 466 | .h1, 467 | h1 { 468 | font-size: 4.498rem; 469 | } 470 | 471 | .h2, 472 | h2 { 473 | font-size: 3.18rem; 474 | } 475 | 476 | .h3, 477 | h3 { 478 | font-size: 2.249rem; 479 | } 480 | 481 | .h4, 482 | h4 { 483 | font-size: 1.591rem; 484 | } 485 | 486 | .posts .post-meta { 487 | padding-bottom: .2em; 488 | } 489 | 490 | .post-link .post-title { 491 | margin-top: .125em; 492 | } 493 | 494 | .posts .post { 495 | margin-bottom: 2.666em; 496 | padding-bottom: 1.333em; 497 | border-bottom: thin solid #f3f3f3; 498 | } 499 | 500 | .posts .post:last-child { 501 | border-bottom: none; 502 | margin-bottom: .666em; 503 | padding-bottom: 0; 504 | } 505 | } 506 | 507 | .share-page { 508 | font-size: 0.65em; 509 | padding: 2em 0 0 0; 510 | } 511 | 512 | .share-page div { 513 | font-size: 1.3em; 514 | } 515 | 516 | footer { 517 | border-top: thin solid #f3f3f3; 518 | } 519 | 520 | footer, 521 | footer .wrap { 522 | color: #7a7a7a; 523 | background-color: #fafafa; 524 | font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; 525 | font-weight: 300; 526 | clear: both; 527 | } 528 | 529 | footer:after { 530 | content: ""; 531 | display: block; 532 | } 533 | 534 | @charset "UTF-8"; 535 | 536 | /*! 537 | Animate.css - http://daneden.me/animate 538 | Licensed under the MIT license - http://opensource.org/licenses/MIT 539 | Copyright (c) 2014 Daniel Eden 540 | */ 541 | 542 | .animated { 543 | -webkit-animation-duration: 1s; 544 | animation-duration: 1s; 545 | -webkit-animation-fill-mode: both; 546 | animation-fill-mode: both; 547 | } 548 | 549 | .animated.infinite { 550 | -webkit-animation-iteration-count: infinite; 551 | animation-iteration-count: infinite; 552 | } 553 | 554 | .animated.hinge { 555 | -webkit-animation-duration: 2s; 556 | animation-duration: 2s; 557 | } 558 | 559 | @-webkit-keyframes fadeInDown { 560 | 0% { 561 | opacity: 0; 562 | -webkit-transform: translateY(-20px); 563 | transform: translateY(-20px); 564 | } 565 | 566 | 100% { 567 | opacity: 1; 568 | -webkit-transform: translateY(0); 569 | transform: translateY(0); 570 | } 571 | } 572 | 573 | @keyframes fadeInDown { 574 | 0% { 575 | opacity: 0; 576 | 577 | -webkit-transform: translateY(-20px) translate3d(0, 0, 0); 578 | transform: translateY(-20px) translate3d(0, 0, 0); 579 | } 580 | 581 | 100% { 582 | opacity: 1; 583 | 584 | -webkit-transform: translateY(0) translate3d(0, 0, 0); 585 | transform: translateY(0) translate3d(0, 0, 0); 586 | } 587 | } 588 | 589 | .fade-in-down { 590 | -webkit-animation-name: fadeInDown; 591 | animation-name: fadeInDown; 592 | } --------------------------------------------------------------------------------