ReactJS

Aus Peter Fuerholz' Wiki
Zur Navigation springen Zur Suche springen

Installation

  • Install NodeJS
  • Install some React libs:
 npm install --save react react-dom babelify babel-preset-react
Some warnings occur but they seem not be harmful...
 sudo npm install -g browserify
 (Probably indirectly needed for 'npm start'.)
 sudo npm install webpack -g
 (Probably indirectly needed for 'npm start'.)
  • Install Grunt:
 sudo npm install -g grunt-cli
  • Install Babel (and its CLI):
 sudo npm install -g babel
 sudo npm install -g babel-cli
 sudo npm install -g babel-preset-react   (not sure if needed)
 sudo npm install -g babel-plugin-syntax-jsx
Babel is a compiler for compiling JSX, ES6 etc. to old-style JavaScript.
Here we have an online Babel translator!

Notable Links

Tutorials

ReactJS libs

Tools

  • webpack packs all necessary JavaScripts in one file together (and does some more).
  • Grunt is an automation/build(?) tool for JavaScript for minification, compilation, unit testing, linting etc.
  • Babel compiles JSX, ES6 to common JavaScript.

Project setup

The project setup depends on the complexity you want to use ReactJS.

Without JSX
Just add in the head-section:
 <script src="fb.me/react-0.14.2.js"></script>
 <script src="fb.me/react-dom-0.14.2.js"></script>
With JSX on runtime (deprecated)
JSX is compiled during runtime (deprecated, use for debugging / test only):
Add translator in the head-section:
 <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
and reference your Javascript file as follows (please notice type="text/babel"):
   <script type="text/babel" src="scripts/example.js"></script>
You could use the JSXTransformer (https://fb.me/JSXTransformer-0.13.3.js) alternatively. (deprecated as well)
Preprocessing JSX
You can use Babel or React-tools for preprocessing the JSX chunks. For both cases you need npm installed.
Setup your project as follows:
 mkdir <my-prj>
 cd <my-prj>
Put following code into file package.json
 {
   "name": "react-basic-commonjs-example",
   "description": "Basic example of using React with CommonJS",
   "main": "index.js",
   "dependencies": {
     "babelify": "^6.3.0",
     "react": "^0.14.0-rc1",
     "react-dom": "^0.14.0-rc1",
     "watchify": "^3.4.0"
   },
   "scripts": {
     "start": "watchify index.js -v -t babelify -o bundle.js"
   }
 }
Create index.html with following content:
 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8" />
     <title>React Tutorial</title>
   </head>
   <body>
     <div id="content"></div>
     <script src="bundle.js"></script>
   </body>
 </html>
Create index.js
 'use strict';
 
 var React = require('react');
 var ReactDOM = require('react-dom');
 
 var Link = React.createClass({ render: function() {
   var url='/' + this.props.label.toLowerCase().trim().replace(' ', '-');
   return <div> <a href={url}>{this.props.label}</a> <br/> </div>}});
 
 var Menu = React.createClass({ render: function() { 
   var menus = ['Home', 'About', 'Services'];

return <div> {menus.map(function(v, i) {return <div key={i}/> <Link label={v}/> </div>})} }});

 var rootEl = document.getElementById('content');
 ReactDOM.render(<Menu/>, rootEl);
and execute npm start which updates bundle.js on-the-fly!
This variant has additionally the advantage that other libraries can be easily added via npm!

Things to remember

JSX:

CSS properties are different (Instead of ... use ...)
class
className
for
forHtml
background-image
backgroundImage
font-size
fontSize
font-family
fontFamily
HTML entities (© — “) cannot be output in dynamic part of JSX
Escape with \u, use String.fromCharCode, use '__html'
{}
introduces a JavaScript-let within JSX
{{}}
shortcut for 'dangerously set inner html', see here

React Component

Properties

Default Properties
create class and provide getDefaultProps method:
 var Button = React.createClass({
   getDefaultProps : function() { return {buttonLabel:'Submit'} },
   render: function() { return <button>{this.props.buttonLabel}</button> } });
Property Type
ReactJS can check that the provided property value matches your proposed data type. Following types are supported:
  • React.PropTypes.string
  • React.PropTypes.number
  • React.PropTypes.bool
  • React.PropTypes.object
  • React.PropTypes.array
  • React.PropTypes.func
Example:
 var Button = React.createClass({ propTypes: { title: React.PropTypes.string }, ... }
Mandatory Property
Configure as mandatory by adding .isRequired
 handler : React.PropTypes.func.isRequired }, ...
Custom Property Validation
 propTypes: { email: 
     function(props, propName, componentName) { 
     var emailRegularExpression = /^([\w.]-1(?;\.[\,[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i
     if (!emailRegularExpression.test(props[propName])) { 
       return new Error('Email validation failed!') 
     }
   }
 }
Children
A component may have arbitrary children. You can iterate through them by accessing them on this.props.children. This property may be an Array or just one object. Use React.Children.count(this.props.children) to count them!

Implicit Objects of React components

this.props
properties provided as JSX parameters; other constant objects
this.state
All user input / dynamic runtime content shall go here
this.type
The type, e.g. 'div'
this.refs
object containing references to the respective React component (defined in JSX by ref-attribute). To access the DOM-node call:
 ReactDOM.findDOMNode(this.refs.<ref-name>)
(this.refs.<ref-name>.getDOMNode() is deprecated!)

Mixins

Mixins allow to derive from other objects ("Mixins allows to reuse code."). Define your object you want to derive from:

 var MyMixin = { ... }

Create class using MyMixin:

 var Component = React.createClass({
   mixins: [MyMixin],
   render: {...} 
 })

React throws an exception if Mixin and Component both implement the same method..

=== Components, Elements and Instances See this article.

Forms

Following form-specific events are supported:

  • onChange
  • onInput
  • onSubmit

(This means you can add the default event handlers as well, e.g. onKeyUp.) There are following form elements including interactive props:

input
value resp. checked when type="checkbox" or type="radio"
textarea
value (don't user inner html!)
select / option
value
option
selected

Input based components (input / textarea)

  • Use parameter defaultValue to prefill them with data.
  • If parameter value is set it is meant to be controlled. Don't do value='Initial value': The user won't be able to change that value!

Things to remember

  • ReactJS updates the UI in following cases:
  • a state value has changed
  • render is called
  • ReactJS classes:
  • React Element: Can be created by React.createElement('div'); or just via JSX: <div>. Each element has following members: type, props, key and ref
  • React Component: React.createClass({ render: function() {...}}); It contains additionally the member state.
  • Drag'n'Drop support: see gaearon and example under /home/pfu/Documents/SW-Dev/React-JS/Examples/Dnd-Example-w-npm
  • 2 things to remember:
  • If things go weird check that you don't have React loaded twice.
  • Don't render into <body>
  • Debug / Runtime versions:
  • minified version = runtime version = no warnings
  • un-minified version = debug version = warnings

Interesting Articles

Redux

  • see here
  • Very good introduction on egghead.io
  • Redux (similar as Flux) is architectural pattern enforced by a library.
  • There is:
  • exactly one state / state tree (in Code: store) for saving the UI state
  • The state is read-only. You have to create (shallow) copies to manipulate it.
  • The UI shall call action creators for manipulating the state. The action creator methods provide the interface the UI can act upon.
  • The action creator methods dispatch an object to a reducer where it is handled. Different reducers can be combined together by 'combineReducers'.
  • The reducers shall "update" the store by creating a shallow copy of its state tree. This means the reducers must be always pure (= no side effects). All changes must be introduced by creating a new object.

The store has following methods:

  • dispatch = handling the objects created by the actions
  • subscribe = listen for state changes (Execute the return value to unsubscribe.)
  • getState = For accessing the state.

An action is called by: dispatch(<action>(<params>)). In case your action does not (immediately) change the store but should e.g. call the server you can use Redux-thunk.

Create a Container component the following way:

const Link = ({ active, children, onClick }) => {
   if (active) {
     return {children};
   }
   return (
     <a href='#' onClick={e => { e.preventDefault(); onClick(); }}>
       {children}
     </a>
   );
 };
 // ownProps contains the props provided to usage of FilterLink (e.g. filter='SHOW_ACTIVE')
 const mapStateToProps = (state, ownProps) => {
   return { active : ownProps.filter === state.visibilityFilter;
 }
 const mapDispatchToProps = () => {
   return {
     onClick: () => {
       dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter });
     }
   };
 }
 const FilterLink = connect(mapStateToProps, mapDispatchToProps)(Link);


React-Redux

  • See here
  • Provides mostly following classes / methods:
Provider
Passes through the dispatch method to every React component. Additionally it allows to access the Redux-store.
connect
Extends presentational React components to functional components. Typically it is used with following parameters:
  • mapStateToProps: If non-null this component get updated when the store changes.
  • mapDispatchToProps: Provide your Redux action creators.
If you want to use connect you should wrap the top component by Provider.

Redux-thunk

  • see here
  • Engage Redux with Redux-thunk with following code:
 thunkMiddleware = require('redux-thunk');() => 
 const { applyMiddleware, createStore } = Redux;
 const logger = createLogger();
 const createStoreWithMiddleware = applyMiddleware(thunkMiddleware, logger)(createStore);
 Store = createStoreWithMiddleware(rootReducer);
  • If you pass a function to dispatch redux-thunk takes this action and executes it. By means of redux-thunk you can run arbitrary code although still calling dispatch. Advantages of this are:
  • (optional) logger can log your specific actions (maybe having important side effects)
  • no need for further provider objects (your UI code gets not sprinkled by XHR code or so on.)
  • your function can have following 2 parameters:
  • dispatch -> react-thunks passes the dispatch object to you
  • getState -> react-thunks passes getState to you
  • The return value of your function does not matter redux nor redux-thunk.

More reasoning about redux-thunk here. redux-thunk kicks itself into Redux

React, Redux and MeteorJS