Skip to content

Instantly share code, notes, and snippets.

@ryanbrunner
Last active March 4, 2021 21:00
Show Gist options
  • Save ryanbrunner/115f55bc90a8fda22d8e95753d5cd242 to your computer and use it in GitHub Desktop.
Save ryanbrunner/115f55bc90a8fda22d8e95753d5cd242 to your computer and use it in GitHub Desktop.
React tips and tricks

React Tips and Tricks

Here's some handy stuff you can use in React!

import classNames from 'classnames';
import React from 'react';
// The classNames library gives you an easy syntax for
// specifying class names dynamically in react. Use it
// whenever you want to conditionally apply classes based
// on props, state, or whatever.
var WidgetListItem = React.createClass({
render: function() {
// Define an object where the keys are the classNames
// you might want to apply, and the values are either
// true (if you want to have the class applied) or false.
const classes = {
'widget': true,
'widget-featured': this.props.widget.featured,
'widget-sale': this.props.widget.discount > 10,
}
// Call the classNames function with the object you defined
// previously.
return <div className={ classNames(classes) }>
Widget!
</div>
}
})
import React from 'react';
// If you have really simple components (basically anything that
// only has a render method), there's a simpler syntax for defining
// them - all you need is a function that returns the JSX for that
// component.
const MySimpleComponent = (props) => <div>{ props.name }</div>;
export default MySimpleComponent;
// Some things to note:
// If you have a more complex render method that has multiple statements,
// you need to wrap the function with { }, and include a return
// statement (this is how arrow functions work, if they are only one
// statement you don't need curly braces or a return keyword)
const MySlightlyMoreComplexComponent = (props) => {
const count = props.widgets.count;
return <div>{ count }</div>;
}
// You can use destructuring to make things even simpler - say you
// only cared about the 'name' prop being passed in:
const SuperSimple = ({name}) => <div>{name}</div>;
import React from 'react';
// You can require all sorts of things with webpack. One super
// handy thing is loading sass using sass-loader.
//
// Before you use this gist, make sure this is in your webpack.config.js:
//
/*
module.exports = {
...
module: {
loaders: [
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
}
};
*/
//
// You'll need to install the `sass-loader`, `css-loader`, `node-sass` and `style-loader` package from npm as well.
// Once you do that, you can require sass from your components like this:
import styles from './styles.scss'
// This will automatically include your styles.
//
// But wait, there's more! You can do something a little special with
// webpack styles.
// Write your css like this:
/*
:local {
.widget {
font-size: 10px;
}
}
*/
// Once you do that, your styles are applicable to *only your component*,
// meaning you'll never override your CSS accidentally ever again. To use
// it in your component, do this:
var MyClassyComponent = React.createClass({
render: function() {
// styles.widget will actually be something like '_23_aKvs-b8bW2Vg3fwHozO'
return <div className={ styles.widget }>
Stylish!
</div>
}
});
import React from 'react';
// When you're updating multiple fields in React, creating a bunch
// of onChange handlers can be a pain. You can take advantage of
// the 'name' property on inputs to combine all your state handlers
// into one property
var MultiInput = React.createClass({
getInitialState: function() {
// This is definitely easier to do if all the state you want
// to update is contained within one property.
return {
model: {
name: '',
email: '',
gender: 'Female'
}
}
},
render: function() {
// Our render is completely normal, there's just a couple of things
// to note here:
//
// - You need to have 'name' properties on your inputs
// - Call the single updateField function for all your onChange handlers
//
// Note that using this for some of your fields doesn't stop you from
// having specific handlers if you need to do something funky.
return <div>
<input name='name' value={ this.state.model.name } onChange={ this.updateField } />
<input name='email' value={ this.state.model.email } onChange={ this.updateField } />
<select name='gender' value={ this.state.model.gender } onChange={ this.updateField }>
<option>Female</option>
<option>Male</option>
<option>Other / Prefer not to Say</option>
</select>
</div>
},
updateField: function(evt) {
var model = this.state.model;
// Here's where the magic happens. Basically we're assuming
// that the name of the input matches a property in the model
// So for instance if the 'email' field was updated,
// model[evt.target.name] would be the same as saying model.email
model[evt.target.name] = evt.target.value;
this.setState({model: model});
}
})
import React from 'react';
// PropTypes are a good way to document what props your component
// expects. If you call a component with PropTypes defined and
// pass invalid info, you'll get a warning in your console.
var LotsOProps = React.createClass({
propTypes: {
name: React.PropTypes.string,
age: React.PropTypes.number,
isAwesome: React.PropTypes.bool.isRequired
}
});
// Or if you're using ES6
class LotsOfProps extends React.Component {
}
LotsOfProps.propTypes = {
name: React.PropTypes.string,
age: React.PropTypes.number,
isAwesome: React.PropTypes.bool.isRequired
}
import React from 'react';
// A common pattern when using react-router is to have an 'app'
// component that all your routes are contained within, that manages
// the database connections that you need and controls props and state.
var App = React.createClass({
getInitialState: function() {
return {
widgets: []
};
},
render: function() {
return <div>
{
// React.cloneElement is basically a way to ensure that
// our subcomponents have the props we want on them.
//
// By passing the firebaseRef, we can allow subcomponents
// to operate on the list of widgets without needing to do
// a callback up to the parent.
React.cloneElement(this.props.children, {
widgets: this.state.widgets,
firebaseRef: this.firebaseRef
})}
</div>
},
// Establish your list of widgets within the App component,
// so your other components don't need to care.
componentDidMount: function() {
this.firebaseRef = firebase.database().ref("widgets");
this.bindAsArray(ref, "widgets");
}
});
var WidgetEntry = React.createClass({
// .. normal render and stuff here
addWidget: function() {
// You can just call the firebaseRef here instead of
// calling back to the parent - the binding will automatically
// take care of things (whether you're using reactFire or
// plain old Firebase)
this.props.firebaseRef.push(this.state.newWidget);
}
})
var WidgetList = React.createClass({
render: function() {
return <ul>
{ this.state.widgets.map((widget) => <li>{ widget.name }</li>)}
</ul>
}
})
// By including all of our subcomponents within App, we know
// that they'll always have the list of widgets as well as
// the firebaseRef available to them.
ReactDOM.render(<Router history={ browserHistory}>
<Route path='/' component={ App }>
<IndexRoute component={ WidgetList } />
<Route path='new' component={ WidgetEntry } />
</Route>
</Router>, document.getElementById('entry'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment