Socket
Socket
Sign inDemoInstall

mobx-react

Package Overview
Dependencies
Maintainers
2
Versions
144
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mobx-react - npm Package Compare versions

Comparing version 3.4.0 to 3.5.0-fix85

9

CHANGELOG.md
# MobX-React Changelog
### 3.5.0
* Introduced `inject("store1", "store2")(component)` as alternative syntax to inject stores. Should address #77, #70
* Introduced the `wrappedComponent` property on injected higher order components, addresses #70, #72
* Fixed #76: error when no stores are provided through context
* Added typings for devTools related features (@benjamingr).
* Added MobX specific propTypes (@mattruby)
* Merged #44, fixes #73: don't re-render if component was somehow unmounted
### 3.4.0

@@ -4,0 +13,0 @@

46

custom.d.ts
/**
* Turns a React component or stateless render function into a reactive component.
*/
import React = require('react');
import React = require("react");
export function observer<P>(clazz: React.StatelessComponent<P>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<any>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ClassicComponentClass<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer<TFunction extends React.ComponentClass<any>>(target: TFunction): TFunction; // decorator signature
export function observer<P, TFunction extends React.ComponentClass<P>>(target: TFunction): TFunction; // decorator signature

@@ -17,6 +17,42 @@ // with stores

export function observer<P>(stores: string[], clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer(stores: string[]): <TFunction extends React.ComponentClass<any>>(target: TFunction) => TFunction; // decorator signature
export function observer<P>(stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
// inject
export function inject<P>(...stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
export function inject<T, P>(storesToProps : (stores: any, nextProps: P, context:any) => T): <TFunction extends React.ComponentClass<T | P>>(target: TFunction) => TFunction; // decorator
export class Provider extends React.Component<any, {}> {
}
}
/**
* Enable dev tool support, makes sure that renderReport emits events.
*/
export function trackComponents():void;
export const renderReporter: RenderReporter;
export interface RenderReporter {
on(handler: (data: IRenderEvent) => void): void;
}
export interface IRenderEvent {
event: "render" | "destroy";
renderTime?: number;
totalTime?: number;
component: React.ReactElement<any>; // Component instance
node: any; // DOMNode
}
/**
* WeakMap DOMNode -> Component instance
*/
export const componentByNodeRegistery: any;
export const propTypes: {
observableArray: React.Requireable<any>;
observableMap: React.Requireable<any>;
observableObject: React.Requireable<any>;
arrayOrObservableArray: React.Requireable<any>;
objectOrObservableObject: React.Requireable<any>;
}

@@ -99,6 +99,19 @@ (function() {

if (!isRenderingPending) {
isRenderingPending = true;
if (typeof self.componentWillReact === "function")
self.componentWillReact();
React.Component.prototype.forceUpdate.call(self)
isRenderingPending = true;
if (self.__$mobxMounted) { // componentWillReact *could* cause component to be unmounted..
React.Component.prototype.forceUpdate.call(self)
} else {
// long story, see:
// https://github.com/mobxjs/mobx-react/issues/85
// https://github.com/mobxjs/mobx-react/pull/44
// https://github.com/mobxjs/mobx-react/commit/7ac924c880747920feaa016a3b4c9c3850449e1a
// https://github.com/mobxjs/mobx-react/commit/cc2e14e2706e93de2de6da1253a3b20692396d7b
// in short: if a rerendering is triggered before the component is mounted,
// forceUpdate is not allowed (which we normally used because if observables change we MUST update)
// but setStates are correctly queued
// this will trigger a warning, but yield the correct rendering, see misc.js: 133
React.Component.prototype.setState.call(self, {}) // fixes 85
}
}

@@ -129,2 +142,3 @@ });

this.render.$mobx && this.render.$mobx.dispose();
this.__$mobxMounted = false;
if (isDevtoolsEnabled) {

@@ -144,2 +158,3 @@ var node = findDOMNode(this);

componentDidMount: function() {
this.__$mobxMounted = true;
if (isDevtoolsEnabled)

@@ -155,6 +170,7 @@ reportRendering(this);

shouldComponentUpdate: function(nextProps, nextState) {
// TODO: if context changed, return true.., see #18
// if props or state did change, but a render was scheduled already, no additional render needs to be scheduled
if (this.render.$mobx && this.render.$mobx.isScheduled() === true)
return false;
// update on any state changes (as is the default)

@@ -201,3 +217,4 @@ if (this.state !== nextState)

} else {
return createStoreInjector(arg1, observer(arg2));
// TODO: deprecate this invocation style
return inject.apply(null, arg1)(observer(arg2));
}

@@ -285,3 +302,3 @@ }

*/
function createStoreInjector(stores, component) {
function createStoreInjector(grabStoresFn, component) {
var Injector = React.createClass({

@@ -293,14 +310,9 @@ displayName: "MobXStoreInjector",

newProps[key] = this.props[key];
var baseStores = this.context.mobxStores;
stores.forEach(function(storeName) {
if (storeName in newProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
newProps[storeName] = baseStores[storeName];
}, this);
newProps = grabStoresFn(this.context.mobxStores || {}, newProps, this.context);
return React.createElement(component, newProps);
}
// TODO: should have shouldComponentUpdate?
});
Injector.contextTypes = { mobxStores: PropTypes.object };
Injector.wrappedComponent = component;
return Injector;

@@ -310,2 +322,66 @@ }

/**
* higher order component that injects stores to a child.
* takes either a varargs list of strings, which are stores read from the context,
* or a function that manually maps the available stores from the context to props:
* storesToProps(mobxStores, props, context) => newProps
*/
function inject(/* fn(stores, nextProps) or ...storeNames */) {
var grabStoresFn;
if (typeof arguments[0] === "function") {
grabStoresFn = arguments[0];
} else {
var storesNames = [];
for (var i = 0; i < arguments.length; i++)
storesNames[i] = arguments[i];
grabStoresFn = grabStoresByName(storesNames);
}
return function(componentClass) {
return createStoreInjector(grabStoresFn, componentClass);
};
}
function grabStoresByName(storeNames) {
return function(baseStores, nextProps) {
storeNames.forEach(function(storeName) {
if (storeName in nextProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
nextProps[storeName] = baseStores[storeName];
});
return nextProps;
}
}
/**
* PropTypes
*/
function observableTypeChecker (type) {
return function(props, propName, componentName) {
if (!mobx['isObservable' + type](props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Expected a mobx observable ' + type + '. Validation failed.'
);
}
};
}
// oneOfType is used for simple isRequired chaining
var propTypes = {
observableArray: React.PropTypes.oneOfType([observableTypeChecker('Array')]),
observableMap: React.PropTypes.oneOfType([observableTypeChecker('Map')]),
observableObject: React.PropTypes.oneOfType([observableTypeChecker('Object')]),
arrayOrObservableArray: React.PropTypes.oneOfType([
React.PropTypes.array,
observableTypeChecker('Array')
]),
objectOrObservableObject: React.PropTypes.oneOfType([
React.PropTypes.object,
observableTypeChecker('Object')
])
};
/**
* Export

@@ -316,2 +392,4 @@ */

Provider: Provider,
inject: inject,
propTypes: propTypes,
reactiveComponent: function() {

@@ -318,0 +396,0 @@ console.warn("[mobx-react] `reactiveComponent` has been renamed to `observer` and will be removed in 1.1.");

/**
* Turns a React component or stateless render function into a reactive component.
*/
import React = require('react');
import React = require("react");
export function observer<P>(clazz: React.StatelessComponent<P>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<any>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ClassicComponentClass<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer<TFunction extends React.ComponentClass<any>>(target: TFunction): TFunction; // decorator signature
export function observer<P, TFunction extends React.ComponentClass<P>>(target: TFunction): TFunction; // decorator signature

@@ -17,6 +17,42 @@ // with stores

export function observer<P>(stores: string[], clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer(stores: string[]): <TFunction extends React.ComponentClass<any>>(target: TFunction) => TFunction; // decorator signature
export function observer<P>(stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
// inject
export function inject<P>(...stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
export function inject<T, P>(storesToProps : (stores: any, nextProps: P, context:any) => T): <TFunction extends React.ComponentClass<T | P>>(target: TFunction) => TFunction; // decorator
export class Provider extends React.Component<any, {}> {
}
}
/**
* Enable dev tool support, makes sure that renderReport emits events.
*/
export function trackComponents():void;
export const renderReporter: RenderReporter;
export interface RenderReporter {
on(handler: (data: IRenderEvent) => void): void;
}
export interface IRenderEvent {
event: "render" | "destroy";
renderTime?: number;
totalTime?: number;
component: React.ReactElement<any>; // Component instance
node: any; // DOMNode
}
/**
* WeakMap DOMNode -> Component instance
*/
export const componentByNodeRegistery: any;
export const propTypes: {
observableArray: React.Requireable<any>;
observableMap: React.Requireable<any>;
observableObject: React.Requireable<any>;
arrayOrObservableArray: React.Requireable<any>;
objectOrObservableObject: React.Requireable<any>;
}

@@ -99,6 +99,19 @@ (function() {

if (!isRenderingPending) {
isRenderingPending = true;
if (typeof self.componentWillReact === "function")
self.componentWillReact();
React.Component.prototype.forceUpdate.call(self)
isRenderingPending = true;
if (self.__$mobxMounted) { // componentWillReact *could* cause component to be unmounted..
React.Component.prototype.forceUpdate.call(self)
} else {
// long story, see:
// https://github.com/mobxjs/mobx-react/issues/85
// https://github.com/mobxjs/mobx-react/pull/44
// https://github.com/mobxjs/mobx-react/commit/7ac924c880747920feaa016a3b4c9c3850449e1a
// https://github.com/mobxjs/mobx-react/commit/cc2e14e2706e93de2de6da1253a3b20692396d7b
// in short: if a rerendering is triggered before the component is mounted,
// forceUpdate is not allowed (which we normally used because if observables change we MUST update)
// but setStates are correctly queued
// this will trigger a warning, but yield the correct rendering, see misc.js: 133
React.Component.prototype.setState.call(self, {}) // fixes 85
}
}

@@ -129,2 +142,3 @@ });

this.render.$mobx && this.render.$mobx.dispose();
this.__$mobxMounted = false;
if (isDevtoolsEnabled) {

@@ -144,2 +158,3 @@ var node = findDOMNode(this);

componentDidMount: function() {
this.__$mobxMounted = true;
if (isDevtoolsEnabled)

@@ -155,6 +170,7 @@ reportRendering(this);

shouldComponentUpdate: function(nextProps, nextState) {
// TODO: if context changed, return true.., see #18
// if props or state did change, but a render was scheduled already, no additional render needs to be scheduled
if (this.render.$mobx && this.render.$mobx.isScheduled() === true)
return false;
// update on any state changes (as is the default)

@@ -201,3 +217,4 @@ if (this.state !== nextState)

} else {
return createStoreInjector(arg1, observer(arg2));
// TODO: deprecate this invocation style
return inject.apply(null, arg1)(observer(arg2));
}

@@ -285,3 +302,3 @@ }

*/
function createStoreInjector(stores, component) {
function createStoreInjector(grabStoresFn, component) {
var Injector = React.createClass({

@@ -293,14 +310,9 @@ displayName: "MobXStoreInjector",

newProps[key] = this.props[key];
var baseStores = this.context.mobxStores;
stores.forEach(function(storeName) {
if (storeName in newProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
newProps[storeName] = baseStores[storeName];
}, this);
newProps = grabStoresFn(this.context.mobxStores || {}, newProps, this.context);
return React.createElement(component, newProps);
}
// TODO: should have shouldComponentUpdate?
});
Injector.contextTypes = { mobxStores: PropTypes.object };
Injector.wrappedComponent = component;
return Injector;

@@ -310,2 +322,66 @@ }

/**
* higher order component that injects stores to a child.
* takes either a varargs list of strings, which are stores read from the context,
* or a function that manually maps the available stores from the context to props:
* storesToProps(mobxStores, props, context) => newProps
*/
function inject(/* fn(stores, nextProps) or ...storeNames */) {
var grabStoresFn;
if (typeof arguments[0] === "function") {
grabStoresFn = arguments[0];
} else {
var storesNames = [];
for (var i = 0; i < arguments.length; i++)
storesNames[i] = arguments[i];
grabStoresFn = grabStoresByName(storesNames);
}
return function(componentClass) {
return createStoreInjector(grabStoresFn, componentClass);
};
}
function grabStoresByName(storeNames) {
return function(baseStores, nextProps) {
storeNames.forEach(function(storeName) {
if (storeName in nextProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
nextProps[storeName] = baseStores[storeName];
});
return nextProps;
}
}
/**
* PropTypes
*/
function observableTypeChecker (type) {
return function(props, propName, componentName) {
if (!mobx['isObservable' + type](props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Expected a mobx observable ' + type + '. Validation failed.'
);
}
};
}
// oneOfType is used for simple isRequired chaining
var propTypes = {
observableArray: React.PropTypes.oneOfType([observableTypeChecker('Array')]),
observableMap: React.PropTypes.oneOfType([observableTypeChecker('Map')]),
observableObject: React.PropTypes.oneOfType([observableTypeChecker('Object')]),
arrayOrObservableArray: React.PropTypes.oneOfType([
React.PropTypes.array,
observableTypeChecker('Array')
]),
objectOrObservableObject: React.PropTypes.oneOfType([
React.PropTypes.object,
observableTypeChecker('Object')
])
};
/**
* Export

@@ -316,2 +392,4 @@ */

Provider: Provider,
inject: inject,
propTypes: propTypes,
reactiveComponent: function() {

@@ -318,0 +396,0 @@ console.warn("[mobx-react] `reactiveComponent` has been renamed to `observer` and will be removed in 1.1.");

/**
* Turns a React component or stateless render function into a reactive component.
*/
import React = require('react');
import React = require("react");
export function observer<P>(clazz: React.StatelessComponent<P>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<any>): React.ClassicComponentClass<P>;
export function observer<P>(renderFunction: (props: P) => React.ReactElement<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ClassicComponentClass<P>): React.ClassicComponentClass<P>;
export function observer<P>(clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer<TFunction extends React.ComponentClass<any>>(target: TFunction): TFunction; // decorator signature
export function observer<P, TFunction extends React.ComponentClass<P>>(target: TFunction): TFunction; // decorator signature

@@ -17,6 +17,42 @@ // with stores

export function observer<P>(stores: string[], clazz: React.ComponentClass<P>): React.ComponentClass<P>;
export function observer(stores: string[]): <TFunction extends React.ComponentClass<any>>(target: TFunction) => TFunction; // decorator signature
export function observer<P>(stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
// inject
export function inject<P>(...stores: string[]): <TFunction extends React.ComponentClass<P>>(target: TFunction) => TFunction; // decorator signature
export function inject<T, P>(storesToProps : (stores: any, nextProps: P, context:any) => T): <TFunction extends React.ComponentClass<T | P>>(target: TFunction) => TFunction; // decorator
export class Provider extends React.Component<any, {}> {
}
}
/**
* Enable dev tool support, makes sure that renderReport emits events.
*/
export function trackComponents():void;
export const renderReporter: RenderReporter;
export interface RenderReporter {
on(handler: (data: IRenderEvent) => void): void;
}
export interface IRenderEvent {
event: "render" | "destroy";
renderTime?: number;
totalTime?: number;
component: React.ReactElement<any>; // Component instance
node: any; // DOMNode
}
/**
* WeakMap DOMNode -> Component instance
*/
export const componentByNodeRegistery: any;
export const propTypes: {
observableArray: React.Requireable<any>;
observableMap: React.Requireable<any>;
observableObject: React.Requireable<any>;
arrayOrObservableArray: React.Requireable<any>;
objectOrObservableObject: React.Requireable<any>;
}

@@ -99,6 +99,19 @@ (function() {

if (!isRenderingPending) {
isRenderingPending = true;
if (typeof self.componentWillReact === "function")
self.componentWillReact();
React.Component.prototype.forceUpdate.call(self)
isRenderingPending = true;
if (self.__$mobxMounted) { // componentWillReact *could* cause component to be unmounted..
React.Component.prototype.forceUpdate.call(self)
} else {
// long story, see:
// https://github.com/mobxjs/mobx-react/issues/85
// https://github.com/mobxjs/mobx-react/pull/44
// https://github.com/mobxjs/mobx-react/commit/7ac924c880747920feaa016a3b4c9c3850449e1a
// https://github.com/mobxjs/mobx-react/commit/cc2e14e2706e93de2de6da1253a3b20692396d7b
// in short: if a rerendering is triggered before the component is mounted,
// forceUpdate is not allowed (which we normally used because if observables change we MUST update)
// but setStates are correctly queued
// this will trigger a warning, but yield the correct rendering, see misc.js: 133
React.Component.prototype.setState.call(self, {}) // fixes 85
}
}

@@ -129,2 +142,3 @@ });

this.render.$mobx && this.render.$mobx.dispose();
this.__$mobxMounted = false;
if (isDevtoolsEnabled) {

@@ -144,2 +158,3 @@ var node = findDOMNode(this);

componentDidMount: function() {
this.__$mobxMounted = true;
if (isDevtoolsEnabled)

@@ -155,6 +170,7 @@ reportRendering(this);

shouldComponentUpdate: function(nextProps, nextState) {
// TODO: if context changed, return true.., see #18
// if props or state did change, but a render was scheduled already, no additional render needs to be scheduled
if (this.render.$mobx && this.render.$mobx.isScheduled() === true)
return false;
// update on any state changes (as is the default)

@@ -201,3 +217,4 @@ if (this.state !== nextState)

} else {
return createStoreInjector(arg1, observer(arg2));
// TODO: deprecate this invocation style
return inject.apply(null, arg1)(observer(arg2));
}

@@ -285,3 +302,3 @@ }

*/
function createStoreInjector(stores, component) {
function createStoreInjector(grabStoresFn, component) {
var Injector = React.createClass({

@@ -293,14 +310,9 @@ displayName: "MobXStoreInjector",

newProps[key] = this.props[key];
var baseStores = this.context.mobxStores;
stores.forEach(function(storeName) {
if (storeName in newProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
newProps[storeName] = baseStores[storeName];
}, this);
newProps = grabStoresFn(this.context.mobxStores || {}, newProps, this.context);
return React.createElement(component, newProps);
}
// TODO: should have shouldComponentUpdate?
});
Injector.contextTypes = { mobxStores: PropTypes.object };
Injector.wrappedComponent = component;
return Injector;

@@ -310,2 +322,66 @@ }

/**
* higher order component that injects stores to a child.
* takes either a varargs list of strings, which are stores read from the context,
* or a function that manually maps the available stores from the context to props:
* storesToProps(mobxStores, props, context) => newProps
*/
function inject(/* fn(stores, nextProps) or ...storeNames */) {
var grabStoresFn;
if (typeof arguments[0] === "function") {
grabStoresFn = arguments[0];
} else {
var storesNames = [];
for (var i = 0; i < arguments.length; i++)
storesNames[i] = arguments[i];
grabStoresFn = grabStoresByName(storesNames);
}
return function(componentClass) {
return createStoreInjector(grabStoresFn, componentClass);
};
}
function grabStoresByName(storeNames) {
return function(baseStores, nextProps) {
storeNames.forEach(function(storeName) {
if (storeName in nextProps) // prefer props over stores
return;
if (!(storeName in baseStores))
throw new Error("MobX observer: Store '" + storeName + "' is not available! Make sure it is provided by some Provider");
nextProps[storeName] = baseStores[storeName];
});
return nextProps;
}
}
/**
* PropTypes
*/
function observableTypeChecker (type) {
return function(props, propName, componentName) {
if (!mobx['isObservable' + type](props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Expected a mobx observable ' + type + '. Validation failed.'
);
}
};
}
// oneOfType is used for simple isRequired chaining
var propTypes = {
observableArray: React.PropTypes.oneOfType([observableTypeChecker('Array')]),
observableMap: React.PropTypes.oneOfType([observableTypeChecker('Map')]),
observableObject: React.PropTypes.oneOfType([observableTypeChecker('Object')]),
arrayOrObservableArray: React.PropTypes.oneOfType([
React.PropTypes.array,
observableTypeChecker('Array')
]),
objectOrObservableObject: React.PropTypes.oneOfType([
React.PropTypes.object,
observableTypeChecker('Object')
])
};
/**
* Export

@@ -316,2 +392,4 @@ */

Provider: Provider,
inject: inject,
propTypes: propTypes,
reactiveComponent: function() {

@@ -318,0 +396,0 @@ console.warn("[mobx-react] `reactiveComponent` has been renamed to `observer` and will be removed in 1.1.");

10

package.json
{
"name": "mobx-react",
"version": "3.4.0",
"version": "3.5.0-fix85",
"description": "React bindings for MobX. Create fully reactive components.",

@@ -32,8 +32,8 @@ "main": "index.js",

"mobx": "^2.2.0",
"react": "^15.1.0",
"react-addons-test-utils": "^15.1.0",
"react-dom": "^15.1.0",
"react": "^15.2.0",
"react-addons-test-utils": "^15.2.0",
"react-dom": "^15.2.0",
"tape": "^4.2.2",
"tape-run": "2.1.0",
"typescript": "^1.7.5"
"typescript": "^1.8.10"
},

@@ -40,0 +40,0 @@ "dependencies": {},

@@ -70,2 +70,5 @@ # mobx-react

It is possible to set a custom `shouldComponentUpdate`, but in general this should be avoid as MobX will by default provide a highly optimized `shouldComponentUpdate` implementation, based on `PureRenderMixin`.
If a custom `shouldComponentUpdate` is provided, it is consulted when the props changes (because the parent passes new props) or the state changes (as a result of calling `setState`), but if an observable used by the rendering is changed, the component will be re-rendered and `shouldComponent` is not consulted.
### `componentWillReact` (lifecycle hook)

@@ -95,4 +98,15 @@

### `Provider` (Experimental)
### `propTypes`
MobX-react provides the following additional `propTypes` which can be used to validate against MobX structures:
* `observableArray`
* `observableMap`
* `observableObject`
* `arrayOrObservableArray`
* `objectOrObservableObject`
### `Provider` and `inject` (Experimental)
_This feature is marked as experimental as the exact api might change in a next minor, pending any community feedback_.

@@ -102,6 +116,9 @@

This is useful if you have things that you don't want to pass through multiple layers of components explicitly.
By passing a string array as first argument to `observer`, observer will pick up the named stores from the context and make them available as props of the decorated component:
`inject` can be used to pick up those stores. It is a higher order component that takes a list of strings and makes those stores available to the wrapped component.
Example (based on the official [context docs](https://facebook.github.io/react/docs/context.html#passing-info-automatically-through-a-tree)):
```javascript
@observer(["color"])
@inject("color") @observer
class Button extends React.Component {

@@ -128,6 +145,2 @@ render() {

class MessageList extends React.Component {
getChildContext() {
return {color: "purple"};
}
render() {

@@ -146,6 +159,35 @@ const children = this.props.messages.map((message) =>

Some note about passing stores around:
Notes:
* If a component ask a store and receives a store via a property with the same name, the property takes precedence. Use this to your advantage when testing!
* Values provided through `Provider` should be final, to avoid issues like mentioned in [React #2517](https://github.com/facebook/react/issues/2517) and [React #3973](https://github.com/facebook/react/pull/3973), where optimizations might stop the propagation of new context. Instead, make sure that if you put things in `context` that might change over time, that they are `@observable` or provide some other means to listen to changes, like callbacks.
* When using both `@inject` and `@observer`, make sure to apply them in the correct order: `observer` should be the inner decorator, `inject` the outher. There might be additional decorators in between.
* The original component wrapped by `inject` is available as the `wrappedComponent` property of created the higher order component.
#### Inject as function
The above example in ES5 would start like:
```javascript
var Button = inject("color")(observer(React.createClass({
/* ... etc ... */
})))
```
#### Strongly typing inject
`inject` also accepts a function (`(allStores, nextProps, nextContext) => nextProps`) that can be used to pick all the desired stores from the available stores like this:
```typescript
import {IUserStore} from "myStore"
@inject((allStores) => ({
userStore: allStores.userStore as IUserStore
}))
class MyComponent extends React.Component<{ userStore?: IUserStore; otherProp: number }, {}> {
/* etc */
}
```
Make sure to mark `userStore` as optional property. It should not (necessarily) be passed in by parent components after all!
## FAQ

@@ -166,3 +208,9 @@

`Warning: forceUpdate(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.`
```
Warning: forceUpdate(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.`
```
-- or --
```
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
```

@@ -169,0 +217,0 @@ Usually this means that (another) component is trying to modify observables used by this components in their `constructor` or `getInitialState` methods.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc