Universe Utilities for react
Provides meteor react modules for universe:modules
Mapping all available modules like require('react/*') and of course require('react') to system modules.
import React from 'react/addons'; import AutoFocusMixin from 'react/lib/AutoFocusMixin';
It's useful for importing components from npm by universe:modules-npm. Package universe:modules-npm allows to replace npm dependencies onto universe:modules dependencies
Universe Mixins for React
AutorunMixin
1import {AutorunMixin} from '{universe:utilities-react}'; 2 3// Any function prefixed with 'autorun' is executed in componentWillMount. 4// It will create Computation object. 5// Computation object is stopped in componentWillUnmount. 6 7export default React.createClass({ 8 mixins: [AutorunMixin], 9 10 // 'Anonymous' autorun. 11 autorun () { 12 // Reactive context here. 13 this.setState({ 14 name: Session.get('name') || 'Anonymous' 15 }); 16 }, 17 18 // 'IsLoggedIn' autorun. 19 autorunIsLoggedIn () { 20 this.setState({ 21 isLoggedIn: !!Metor.userId() 22 }); 23 }, 24 25 render () { 26 return ( 27 <div> 28 <p>Session variable: {this.state.name}</p> 29 <p>Is user logged in? {'' + this.state.isLoggedIn}</p> 30 <button onClick={this.invalidate}>Click to invalidate autoruns</button> 31 </div> 32 ); 33 }, 34 35 invalidate () { 36 this.autorunComputation.invalidate(); 37 this.autorunIsLoggedInComputation.invalidate(); 38 } 39});
DualLinkMixin
1import {DualLinkMixin} from '{universe:utilities-react}'; 2 3// Create or get dualLink from cache. 4// var dualLink = this.dualLink(name = 'default') 5// 6// Overwrite local state with object 7// dualLink.setLocal(object) 8// Overwrite remote state with object 9// dualLink.setRemote(object) 10// 11// Overwrite field in local state with value 12// dualLink.setLocal(field, value) 13// Overwrite field in remote state with value 14// dualLink.setRemote(field, value) 15// 16// Removes local state 17// dualLink.clear() 18// 19// Check for any value in both state 20// dualLink.isEmpty() 21// 22// Creates value link (changes are saved in local state) 23// dualLink.valueLink(field) 24// 25// Get two states merged 26// dualLink.get() 27// Get field from both states (local state has higher priority than remote) 28// dualLink.get(field) 29// 30// Get field from local state 31// dualLink.getLocal(field) 32// Get field from remote state 33// dualLink.getRemote(field) 34 35export React.createClass({ 36 mixins: [DualLinkMixin], 37 38 componentWillMount () { 39 this.dualLink().setRemote(this.props.user); 40 }, 41 42 componentWillReceiveProps (props) { 43 this.dualLink().clear(); 44 this.dualLink().setRemote(props.user); 45 }, 46 47 render () { 48 const dualLink = this.dualLink(); 49 50 if (dualLink.isEmpty()) { 51 return ( 52 <p>Loading...</p> 53 ); 54 } 55 56 return ( 57 <div> 58 <p>Id: {dualLink.get('id')}</p> 59 <p>Name: {dualLink.get('name')}</p> 60 </div> 61 ); 62 } 63});
SubscriptionMixin
1import {AutorunMixin, SubscriptionMixin} from '{universe:utilities-react}'; 2 3// Subscribe for publication 4// this.subscribe(publicationName, ...args) 5// 6// Check for readiness of single subscription 7// this.subscriptionReady(publicationName) 8// 9// Check for readiness of all subscriptions 10// this.subscriptionsReady() 11 12export default React.createClass({ 13 mixins: [SubscriptionMixin, AutorunMixin], 14 15 autorunUsers () { 16 this.subscribe('users'); 17 this.setState({ 18 users: Meteor.users.find().fetch() 19 }); 20 }, 21 22 render () { 23 if (!this.subscriptionsReady()) { 24 return ( 25 <p>Loading...</p> 26 ); 27 } 28 29 return ( 30 <ul> 31 {this.state.users} 32 </ul> 33 ); 34 } 35});
Complete example
1import {AutorunMixin, DualLinkMixin, SubscriptionMixin} from '{universe:utilities-react}'; 2 3export default React.createClass({ 4 mixins: [SubscriptionMixin, DualLinkMixin, AutorunMixin], 5 6 propTypes: { 7 id: React.PropTypes.string.isRequired 8 }, 9 10 autorunPost () { 11 const id = this.props.id; 12 13 this.subscribe('post', id); 14 this.dualLink().setRemote(Posts.findOne(id)); 15 }, 16 17 render () { 18 if (!this.subscriptionsReady()) { 19 return ( 20 <p>Loading...</p> 21 ); 22 } 23 24 const dualLink = this.dualLink(); 25 26 return ( 27 <div> 28 <input type="text" valueLink={dualLink.get('title')}> 29 <input type="text" valueLink={dualLink.get('text')}> 30 <button onClick={this.submit}>Save</button> 31 </div> 32 ); 33 }, 34 35 submit () { 36 Posts.update({ 37 _id: this.props.id 38 }, { 39 $set: this.dualLink().get() 40 }); 41 } 42});
Helpers
classNames
A simple utility for conditionally joining classNames together
1import {classNames} from '{universe:utilities-react}'; 2 3classNames('foo', 'bar'); // => 'foo bar' 4classNames('foo', { bar: true }); // => 'foo bar' 5classNames({ foo: true }, { bar: true }); // => 'foo bar' 6classNames({ foo: true, bar: true }); // => 'foo bar' 7 8// lots of arguments of various types 9classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }) // => 'foo bar baz quux' 10 11// other falsy values are just ignored 12classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
- based on JedWatson/classnames
deepEqual
Node's assert.deepEqual() algorithm as a standalone module. This module is around 5 times faster than wrapping assert.deepEqual() in a try/catch.
1import {deepEqual} from '{universe:utilities-react}'; 2 3console.dir([ 4 equal( 5 { a : [ 2, 3 ], b : [ 4 ] }, 6 { a : [ 2, 3 ], b : [ 4 ] } 7 ), 8 equal( 9 { x : 5, y : [6] }, 10 { x : 5, y : 6 } 11 ) 12]);
deepEqual(a, b, opts) Compare objects a and b, returning whether they are equal according to a recursive equality algorithm.
If opts.strict is true, use strict equality (===) to compare leaf nodes. The default is to use coercive equality (==) because that's how assert.deepEqual() works by default.
- based on substack/node-deep-equal
executionEnvironment
Simple helpers around environment with information like: canUseDOM, canUseWorkers, canUseEventListeners, canUseViewport
1import {executionEnvironment} from '{universe:utilities-react}'; 2 3console.log(executionEnvironment.canUseDOM); 4console.log(executionEnvironment.canUseWorkers); 5console.log(executionEnvironment.canUseEventListeners); 6console.log(executionEnvironment.canUseViewport);
objectAssign
Ponyfill: A polyfill that doesn't overwrite the native method
1import {objectAssign} from '{universe:utilities-react}'; 2objectAssign({foo: 0}, {bar: 1}); 3//=> {foo: 0, bar: 1} 4 5// multiple sources 6objectAssign({foo: 0}, {bar: 1}, {baz: 2}); 7//=> {foo: 0, bar: 1, baz: 2} 8 9// overwrites equal keys 10objectAssign({foo: 0}, {foo: 1}, {foo: 2}); 11//=> {foo: 2} 12 13// ignores null and undefined sources 14objectAssign({foo: 0}, null, {bar: 1}, undefined); 15//=> {foo: 0, bar: 1}
objectAssign(target, source, [source, ...])
Assigns enumerable own properties of source objects to the target object and returns the target object. Additional source objects will overwrite previous ones.
- more here: ES6 spec - Object.assign
- based on sindresorhus/object-assign
cloneWithProps
Stand-alone React cloneWithProps util that works with multiple versions of React
1import {cloneWithProps} from '{universe:utilities-react}'; 2cloneWithProps(<MyComponent oldProp='hi'/> { newProp: 'hello' })
This is tested with React 0.9 to 0.13, and adds a trivial amount of code to get everything to work.
- based on react-clonewithprops
deepExtend
Recursive object extending.
1import {deepExtend} from '{universe:utilities-react}'; 2var obj1 = { 3 a: 1, 4 b: 2, 5 d: { 6 a: 1, 7 b: [], 8 c: { test1: 123, test2: 321 } 9 }, 10 f: 5, 11 g: 123, 12 i: 321, 13 j: [1, 2] 14}; 15var obj2 = { 16 b: 3, 17 c: 5, 18 d: { 19 b: { first: 'one', second: 'two' }, 20 c: { test2: 222 } 21 }, 22 e: { one: 1, two: 2 }, 23 f: [], 24 g: (void 0), 25 h: /abc/g, 26 i: null, 27 j: [3, 4] 28}; 29 30deepExtend(obj1, obj2); 31 32console.log(obj1); 33/* 34{ a: 1, 35 b: 3, 36 d: 37 { a: 1, 38 b: { first: 'one', second: 'two' }, 39 c: { test1: 123, test2: 222 } }, 40 f: null, 41 g: undefined, 42 c: 5, 43 e: { one: 1, two: 2 }, 44 h: /abc/g, 45 i: null, 46 j: [3, 4] } 47*/
- based on unclechu/node-deep-extend