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'; import ReactDOM from 'react-dom'; 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
Gives possibility of using from autorun functionality in React components. So, using this mixin you can reactively get data from any reactive source in meteor and set them to your component state. So, you can use autoruns almost like in blaze.
In our opinion, this is better solution than solution proposed by mdg, because is much lighter and it doesn't hack React data flow.
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});
SubscriptionMixin
Gives possibility of making subscriptions from your React component. Subscription (like in blaze) is joined with life cycle of React component. So you don't need remember about stopping subscription.
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 or selected subscription handler 7// this.subscriptionReady(publicationName[, subscriptionHandlerId]) 8// 9// Check for readiness of all subscriptions 10// this.subscriptionsReady() 11// 12// Stops all subscriptions 13// this.subscriptionsStop() 14// 15// Stops one subscription or selected subscription handler 16// this.subscriptionStop(publicationName[, subscriptionHandlerId]) 17 18export default React.createClass({ 19 mixins: [SubscriptionMixin, AutorunMixin], 20 21 autorunUsers () { 22 this.subscribe('users'); 23 this.setState({ 24 users: Meteor.users.find().fetch() 25 }); 26 }, 27 28 render () { 29 if (!this.subscriptionsReady()) { 30 return ( 31 <p>Loading...</p> 32 ); 33 } 34 35 return ( 36 <ul> 37 {this.state.users} 38 </ul> 39 ); 40 } 41});
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});
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
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