From f5d4050e67e79590b2512e6aabcdda1b71d54eff Mon Sep 17 00:00:00 2001 From: Roger Studner Date: Fri, 30 Oct 2015 21:04:51 -0400 Subject: [PATCH 1/6] ES6 all React stuff. --- client/app/components/Comment.jsx | 13 +++-- client/app/components/CommentBox.jsx | 19 ++++--- client/app/components/CommentForm.jsx | 50 +++++++++---------- client/app/components/CommentList.jsx | 14 +++--- client/app/components/CommentScreen.jsx | 12 ++--- client/app/components/SimpleCommentScreen.jsx | 32 ++++++------ client/app/reducers/commentsReducer.js | 2 +- client/app/startup/ClientApp.jsx | 9 ++-- client/app/startup/ServerApp.jsx | 9 ++-- client/app/stores/commentsStore.js | 4 +- 10 files changed, 76 insertions(+), 88 deletions(-) diff --git a/client/app/components/Comment.jsx b/client/app/components/Comment.jsx index e3b40d1f..a358bd80 100644 --- a/client/app/components/Comment.jsx +++ b/client/app/components/Comment.jsx @@ -1,13 +1,12 @@ import React, { PropTypes } from 'react'; import marked from 'marked'; -const Comment = React.createClass({ - displayName: 'Comment', - - propTypes: { +class Comment extends React.Component { + static displayName = 'Comment'; + static propTypes = { author: PropTypes.string.isRequired, text: PropTypes.string.isRequired, - }, + }; render() { const { author, text } = this.props; @@ -20,7 +19,7 @@ const Comment = React.createClass({ ); - }, -}); + } +} export default Comment; diff --git a/client/app/components/CommentBox.jsx b/client/app/components/CommentBox.jsx index 21e805a2..9596048f 100644 --- a/client/app/components/CommentBox.jsx +++ b/client/app/components/CommentBox.jsx @@ -3,28 +3,27 @@ import React, { PropTypes } from 'react'; import CommentForm from './CommentForm'; import CommentList from './CommentList'; -const CommentBox = React.createClass({ - displayName: 'CommentBox', - - propTypes: { +class CommentBox extends React.Component { + static displayName = 'CommentBox'; + static propTypes = { pollInterval: PropTypes.number.isRequired, actions: PropTypes.object.isRequired, data: PropTypes.object.isRequired, - }, + }; componentDidMount() { const { fetchComments } = this.props.actions; fetchComments(); setInterval(fetchComments, this.props.pollInterval); - }, + } ajaxCounter() { return this.props.data.get('ajaxCounter'); - }, + } isSendingAjax() { return this.ajaxCounter() > 0; - }, + } render() { const { actions, data } = this.props; @@ -49,7 +48,7 @@ const CommentBox = React.createClass({ /> ); - }, -}); + } +} export default CommentBox; diff --git a/client/app/components/CommentForm.jsx b/client/app/components/CommentForm.jsx index cbe5c755..f0c5ae15 100644 --- a/client/app/components/CommentForm.jsx +++ b/client/app/components/CommentForm.jsx @@ -10,31 +10,27 @@ import ReactCSSTransitionGroup from 'react/lib/ReactCSSTransitionGroup'; const emptyComment = { author: '', text: '' }; const textPlaceholder = 'Say something using markdown...'; -const CommentForm = React.createClass({ - displayName: 'CommentForm', +class CommentForm extends React.Component { + state = { + formMode: 0, + comment: emptyComment, + }; - propTypes: { + static displayName = 'CommentForm'; + + static propTypes = { ajaxSending: PropTypes.bool.isRequired, actions: PropTypes.object.isRequired, error: PropTypes.any, - }, - - getInitialState() { - return { - formMode: 0, - comment: emptyComment, - }; - }, + }; - handleSelect(selectedKey) { + handleSelect = (selectedKey) => { this.setState({ formMode: selectedKey }); - }, + }; - handleChange() { + handleChange = () => { let comment; - // This could also be done using ReactLink: - // http://facebook.github.io/react/docs/two-way-binding-helpers.html if (this.state.formMode < 2) { comment = { author: this.refs.author.getValue(), @@ -50,17 +46,17 @@ const CommentForm = React.createClass({ } this.setState({ comment }); - }, + }; - handleSubmit(e) { + handleSubmit = (e) => { e.preventDefault(); const { actions } = this.props; actions .submitComment(this.state.comment) .then(this.resetAndFocus); - }, + }; - resetAndFocus() { + resetAndFocus = () => { // Don't reset a form that didn't submit, this results in data loss if (this.props.error) return; @@ -75,7 +71,7 @@ const CommentForm = React.createClass({ } ref.focus(); - }, + } formHorizontal() { return ( @@ -117,7 +113,7 @@ const CommentForm = React.createClass({ ); - }, + } formStacked() { return ( @@ -151,7 +147,7 @@ const CommentForm = React.createClass({ ); - }, + } formInline() { return ( @@ -195,7 +191,7 @@ const CommentForm = React.createClass({ ); - }, + } errorWarning() { // If there is no error, there is nothing to add to the DOM @@ -206,7 +202,7 @@ const CommentForm = React.createClass({ A server error prevented your comment from being saved. Please try again. ); - }, + } render() { let inputForm; @@ -241,7 +237,7 @@ const CommentForm = React.createClass({ {inputForm} ); - }, -}); + } +} export default CommentForm; diff --git a/client/app/components/CommentList.jsx b/client/app/components/CommentList.jsx index b4321728..4b2a0d22 100644 --- a/client/app/components/CommentList.jsx +++ b/client/app/components/CommentList.jsx @@ -5,13 +5,13 @@ import ReactCSSTransitionGroup from 'react/lib/ReactCSSTransitionGroup'; import Comment from './Comment'; -const CommentList = React.createClass({ - displayName: 'CommentList', +class CommentList extends React.Component { + static displayName = 'CommentList'; - propTypes: { + static propTypes = { $$comments: PropTypes.instanceOf(Immutable.List).isRequired, error: PropTypes.any, - }, + }; errorWarning() { // If there is no error, there is nothing to add to the DOM @@ -22,7 +22,7 @@ const CommentList = React.createClass({ A server error prevented loading comments. Please try again. ); - }, + } render() { const { $$comments } = this.props; @@ -53,7 +53,7 @@ const CommentList = React.createClass({ ); - }, -}); + } +} export default CommentList; diff --git a/client/app/components/CommentScreen.jsx b/client/app/components/CommentScreen.jsx index 40439789..923f2b7d 100644 --- a/client/app/components/CommentScreen.jsx +++ b/client/app/components/CommentScreen.jsx @@ -9,13 +9,13 @@ function select(state) { return { data: state.$$commentsStore }; } -const CommentScreen = React.createClass({ - displayName: 'CommentScreen', +class CommentScreen extends React.Component { + static displayName = 'CommentScreen'; - propTypes: { + static propTypes = { dispatch: PropTypes.func.isRequired, data: PropTypes.object.isRequired, - }, + }; render() { const { dispatch, data } = this.props; @@ -42,8 +42,8 @@ const CommentScreen = React.createClass({ ); - }, -}); + } +} // Don't forget to actually use connect! export default connect(select)(CommentScreen); diff --git a/client/app/components/SimpleCommentScreen.jsx b/client/app/components/SimpleCommentScreen.jsx index 00e90233..e8b7713f 100644 --- a/client/app/components/SimpleCommentScreen.jsx +++ b/client/app/components/SimpleCommentScreen.jsx @@ -5,29 +5,27 @@ import CommentForm from './CommentForm'; import CommentList from './CommentList'; import metaTagsManager from '../utils/metaTagsManager'; -const SimpleCommentScreen = React.createClass({ - displayName: 'SimpleCommentScreen', +class SimpleCommentScreen extends React.Component { + state = { + $$comments: Immutable.fromJS([]), + ajaxSending: false, + fetchCommentsError: null, + submitCommentError: null, + }; - getInitialState() { - return { - $$comments: Immutable.fromJS([]), - ajaxSending: false, - fetchCommentsError: null, - submitCommentError: null, - }; - }, + static displayName = 'SimpleCommentScreen'; componentDidMount() { this.fetchComments(); - }, + } fetchComments() { return request.get('comments.json', { responseType: 'json' }) .then(res => this.setState({ $$comments: Immutable.fromJS(res.data) })) .catch(error => this.setState({ fetchCommentsError: error })); - }, + } - handleCommentSubmit(comment) { + handleCommentSubmit = (comment) => { this.setState({ ajaxSending: true }); const requestConfig = { @@ -53,7 +51,7 @@ const SimpleCommentScreen = React.createClass({ ajaxSending: false, }); }); - }, + }; render() { return ( @@ -65,7 +63,7 @@ const SimpleCommentScreen = React.createClass({

); - }, -}); + } +} export default SimpleCommentScreen; diff --git a/client/app/reducers/commentsReducer.js b/client/app/reducers/commentsReducer.js index 5ed231b1..239b024a 100644 --- a/client/app/reducers/commentsReducer.js +++ b/client/app/reducers/commentsReducer.js @@ -11,7 +11,7 @@ export const $$initialState = Immutable.fromJS({ submitCommentError: null, }); -export default function commentsReducer($$state = $$initialState, action) { +export default function commentsReducer($$state = $$initialState, action = null) { const { type, comment, comments, error } = action; switch (type) { diff --git a/client/app/startup/ClientApp.jsx b/client/app/startup/ClientApp.jsx index b8035b7d..9f5744cc 100644 --- a/client/app/startup/ClientApp.jsx +++ b/client/app/startup/ClientApp.jsx @@ -6,12 +6,11 @@ import CommentScreen from '../components/CommentScreen'; const App = props => { const store = createStore(props); - const reactComponent = ( - - - + return ( + + + ); - return reactComponent; }; // Export is needed for the hot reload server diff --git a/client/app/startup/ServerApp.jsx b/client/app/startup/ServerApp.jsx index 6786a0be..612bb058 100644 --- a/client/app/startup/ServerApp.jsx +++ b/client/app/startup/ServerApp.jsx @@ -6,12 +6,11 @@ import CommentScreen from '../components/CommentScreen'; const App = props => { const store = createStore(props); - const reactComponent = ( - - - + return ( + + + ); - return reactComponent; }; export default App; diff --git a/client/app/stores/commentsStore.js b/client/app/stores/commentsStore.js index 0622dce7..5d1e60ac 100644 --- a/client/app/stores/commentsStore.js +++ b/client/app/stores/commentsStore.js @@ -17,8 +17,6 @@ export default props => { const composedStore = compose( applyMiddleware(thunkMiddleware, loggerMiddleware) ); - const storeCreator = composedStore(createStore); - const store = storeCreator(reducer, initialState); - return store; + return composedStore(createStore)(reducer, initialState); }; From 84de8d1e8b48e64796964916987fbba71674f4cf Mon Sep 17 00:00:00 2001 From: Roger Studner Date: Mon, 2 Nov 2015 07:19:37 -0500 Subject: [PATCH 2/6] updated to constructor/bind syntax after talking with Alex I also renamed the "component internal non-react workflow methods" to have a leading _ per multiple best-practices guides etc. --- client/app/components/CommentBox.jsx | 18 +++-- client/app/components/CommentForm.jsx | 68 +++++++++++-------- client/app/components/CommentList.jsx | 11 ++- client/app/components/SimpleCommentScreen.jsx | 28 +++++--- 4 files changed, 77 insertions(+), 48 deletions(-) diff --git a/client/app/components/CommentBox.jsx b/client/app/components/CommentBox.jsx index 9596048f..80da0185 100644 --- a/client/app/components/CommentBox.jsx +++ b/client/app/components/CommentBox.jsx @@ -4,6 +4,14 @@ import CommentForm from './CommentForm'; import CommentList from './CommentList'; class CommentBox extends React.Component { + constructor(props, context) { + super(props, context); + this.state = {}; + + this._ajaxCounter = this._ajaxCounter.bind(this); + this._isSendingAjax = this._isSendingAjax.bind(this); + } + static displayName = 'CommentBox'; static propTypes = { pollInterval: PropTypes.number.isRequired, @@ -17,12 +25,12 @@ class CommentBox extends React.Component { setInterval(fetchComments, this.props.pollInterval); } - ajaxCounter() { + _ajaxCounter() { return this.props.data.get('ajaxCounter'); } - isSendingAjax() { - return this.ajaxCounter() > 0; + _isSendingAjax() { + return this._ajaxCounter() > 0; } render() { @@ -31,14 +39,14 @@ class CommentBox extends React.Component { return (

- Comments { this.isSendingAjax() && `SENDING AJAX REQUEST! Ajax Counter is ${this.ajaxCounter()}` } + Comments { this._isSendingAjax() && `SENDING AJAX REQUEST! Ajax Counter is ${this._ajaxCounter()}` }

Text take Github Flavored Markdown. Comments older than 24 hours are deleted. Name is preserved, Text is reset, between submits.

diff --git a/client/app/components/CommentForm.jsx b/client/app/components/CommentForm.jsx index f0c5ae15..a3c71cce 100644 --- a/client/app/components/CommentForm.jsx +++ b/client/app/components/CommentForm.jsx @@ -11,10 +11,18 @@ const emptyComment = { author: '', text: '' }; const textPlaceholder = 'Say something using markdown...'; class CommentForm extends React.Component { - state = { - formMode: 0, - comment: emptyComment, - }; + constructor(props, context) { + super(props, context); + this.state = { + formMode: 0, + comment: emptyComment, + }; + + this._handleSelect = this._handleSelect.bind(this); + this._handleChange = this._handleChange.bind(this); + this._handleSubmit = this._handleSubmit.bind(this); + this._resetAndFocus = this._resetAndFocus.bind(this); + } static displayName = 'CommentForm'; @@ -24,11 +32,11 @@ class CommentForm extends React.Component { error: PropTypes.any, }; - handleSelect = (selectedKey) => { + _handleSelect(selectedKey) { this.setState({ formMode: selectedKey }); - }; + } - handleChange = () => { + _handleChange() { let comment; if (this.state.formMode < 2) { @@ -46,17 +54,17 @@ class CommentForm extends React.Component { } this.setState({ comment }); - }; + } - handleSubmit = (e) => { + _handleSubmit(e) { e.preventDefault(); const { actions } = this.props; actions .submitComment(this.state.comment) - .then(this.resetAndFocus); - }; + .then(this._resetAndFocus); + } - resetAndFocus = () => { + _resetAndFocus() { // Don't reset a form that didn't submit, this results in data loss if (this.props.error) return; @@ -73,11 +81,11 @@ class CommentForm extends React.Component { ref.focus(); } - formHorizontal() { + _formHorizontal() { return (

-
+
@@ -115,18 +123,18 @@ class CommentForm extends React.Component { ); } - formStacked() { + _formStacked() { return (

- +
- + @@ -163,7 +171,7 @@ class CommentForm extends React.Component { placeholder="Your Name" ref="inlineAuthor" value={this.state.comment.author} - onChange={this.handleChange} + onChange={this._handleChange} disabled={this.props.ajaxSending} /> @@ -174,7 +182,7 @@ class CommentForm extends React.Component { placeholder={textPlaceholder} ref="inlineText" value={this.state.comment.text} - onChange={this.handleChange} + onChange={this._handleChange} disabled={this.props.ajaxSending} /> @@ -193,7 +201,7 @@ class CommentForm extends React.Component { ); } - errorWarning() { + _errorWarning() { // If there is no error, there is nothing to add to the DOM if (!this.props.error) return undefined; return ( @@ -208,13 +216,13 @@ class CommentForm extends React.Component { let inputForm; switch (this.state.formMode) { case 0: - inputForm = this.formHorizontal(); + inputForm = this._formHorizontal(); break; case 1: - inputForm = this.formStacked(); + inputForm = this._formStacked(); break; case 2: - inputForm = this.formInline(); + inputForm = this._formInline(); break; default: throw new Error(`Unknown form mode: ${this.state.formMode}.`); @@ -226,10 +234,10 @@ class CommentForm extends React.Component { transitionEnterTimeout={300} transitionLeaveTimeout={300} > - {this.errorWarning()} + {this._errorWarning()} -