Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace obsolete react context #663

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions packages/fluxible-addons-react/src/FluxibleComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@
* Copyright 2015, Yahoo Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import { Component, cloneElement } from 'react';
import { func, object, node } from 'prop-types';
import { Component, cloneElement, createElement } from 'react';
import { object, node } from 'prop-types';
import { FluxibleProvider } from './FluxibleContext';

class FluxibleComponent extends Component {
getChildContext() {
return {
getStore: this.props.context.getStore,
executeAction: this.props.context.executeAction
};
}

render() {
return cloneElement(this.props.children, {
context: this.props.context
});
const { children, context } = this.props;
const childrenWithContext = cloneElement(children, { context });
return createElement(FluxibleProvider, { context }, childrenWithContext);
}
}

Expand All @@ -25,9 +19,4 @@ FluxibleComponent.propTypes = {
context: object.isRequired
};

FluxibleComponent.childContextTypes = {
executeAction: func.isRequired,
getStore: func.isRequired
};

export default FluxibleComponent;
39 changes: 39 additions & 0 deletions packages/fluxible-addons-react/src/FluxibleContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Component, createContext, createElement } from 'react';
import { arrayOf, node, object, string } from 'prop-types';

export const FluxibleContext = createContext({
executeAction: () => {},
getStore: () => {},
});

export class FluxibleProvider extends Component {
constructor(props) {
super(props);

const state = {
executeAction: this.props.context.executeAction,
getStore: this.props.context.getStore,
};

this.props.plugins.forEach(plugin => {
state[plugin] = this.props.context[plugin];
});

this.state = state;
}

render() {
const props = { value: this.state };
return createElement(FluxibleContext.Provider, props, this.props.children);
}
}

FluxibleProvider.propTypes = {
children: node.isRequired,
context: object.isRequired,
plugins: arrayOf(string)
};

FluxibleProvider.defaultProps = {
plugins: []
};
11 changes: 3 additions & 8 deletions packages/fluxible-addons-react/src/connectToStores.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import { Component as ReactComponent, createRef, createElement } from 'react';
import { func } from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import { FluxibleContext } from './FluxibleContext';

/**
* Registers change listeners and retrieves state from stores using the `getStateFromStores`
Expand All @@ -25,11 +25,9 @@ import hoistNonReactStatics from 'hoist-non-react-statics';
* @param {array} stores List of stores to listen for changes
* @param {function} getStateFromStores function that receives all stores and should return
* the full state object. Receives `stores` hash and component `props` as arguments
* @param {Object} [customContextTypes] additional `contextTypes` that could be accessed from your `getStateFromStores`
* function
* @returns {React.Component} or {Function} if using decorator pattern
*/
function connectToStores(Component, stores, getStateFromStores, customContextTypes) {
function connectToStores(Component, stores, getStateFromStores) {
class StoreConnector extends ReactComponent {
constructor(props, context) {
super(props, context);
Expand Down Expand Up @@ -75,10 +73,7 @@ function connectToStores(Component, stores, getStateFromStores, customContextTyp

StoreConnector.displayName = `storeConnector(${Component.displayName || Component.name || 'Component'})`;

StoreConnector.contextTypes = {
getStore: func.isRequired,
...customContextTypes
},
StoreConnector.contextType = FluxibleContext;

StoreConnector.WrappedComponent = Component;

Expand Down
17 changes: 7 additions & 10 deletions packages/fluxible-addons-react/src/createElementWithContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,15 @@ function createElementWithContext(fluxibleContext, props) {
if (!Component) {
throw new Error('A top-level component was not passed to the Fluxible constructor.');
}

const context = fluxibleContext.getComponentContext();

if (Component.displayName && Component.displayName.includes('contextProvider')) {
return createElement(
Component,
{context: fluxibleContext.getComponentContext(), ...props},
);
return createElement(Component, { context, ...props});
}
const componentInstance = createElement(Component, props);
return createElement(
FluxibleComponent,
{context: fluxibleContext.getComponentContext()},
componentInstance
);

const children = createElement(Component, props);
return createElement(FluxibleComponent, { context }, children);
}

export default createElementWithContext;
1 change: 1 addition & 0 deletions packages/fluxible-addons-react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as batchedUpdatePlugin } from './batchedUpdatePlugin';
export { default as connectToStores } from './connectToStores';
export { default as createElementWithContext } from './createElementWithContext';
export { default as provideContext } from './provideContext';
export { FluxibleContext } from './FluxibleContext';
31 changes: 8 additions & 23 deletions packages/fluxible-addons-react/src/provideContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { Component as ReactComponent, createRef, createElement } from 'react';
import { func, object } from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import { FluxibleProvider } from './FluxibleContext';

/**
* Provides context prop to all children as React context
Expand All @@ -16,43 +17,27 @@ import hoistNonReactStatics from 'hoist-non-react-statics';
*
* @method provideContext
* @param {React.Component} [Component] component to wrap
* @param {object} customContextTypes Custom contextTypes to add
* @returns {React.Component} or {Function} if using decorator pattern
* @param {array} [plugins] list of plugins names to inject into the context
* @returns {React.Component}
*/
function provideContext(Component, customContextTypes) {
function provideContext(Component, plugins) {
class ContextProvider extends ReactComponent {
constructor(props) {
super(props);
this.wrappedElementRef = createRef();
}

getChildContext() {
const childContext = {
executeAction: this.props.context.executeAction,
getStore: this.props.context.getStore
};
if (customContextTypes) {
Object.keys(customContextTypes).forEach(key => {
childContext[key] = this.props.context[key];
});
}
return childContext;
}

render() {
const props = (Component.prototype && Component.prototype.isReactComponent)
? {ref: this.wrappedElementRef}
: null;
return createElement(Component, {...this.props, ...props});

const { context } = this.props;
const children = createElement(Component, {...this.props, ...props});
return createElement(FluxibleProvider, { context, plugins }, children);
}
}

ContextProvider.childContextTypes = {
executeAction: func.isRequired,
getStore: func.isRequired,
...customContextTypes
};

ContextProvider.propTypes = {
context: object.isRequired
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
import { JSDOM } from 'jsdom';
import createMockComponentContext from 'fluxible/utils/createMockComponentContext';

import { connectToStores, provideContext } from '../../../';
import { connectToStores, provideContext, FluxibleContext } from '../../../';
import FooStore from '../../fixtures/stores/FooStore';
import BarStore from '../../fixtures/stores/BarStore';

Expand All @@ -35,9 +35,7 @@ describe('fluxible-addons-react', () => {

it('should get the state from the stores', (done) => {
class Component extends React.Component {
static contextTypes = {
executeAction: PropTypes.func.isRequired,
}
static contextType = FluxibleContext

constructor() {
super();
Expand Down
15 changes: 5 additions & 10 deletions packages/fluxible-addons-react/tests/unit/lib/provideContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { renderToString } from 'react-dom/server';
import PropTypes from 'prop-types';
import { JSDOM } from 'jsdom';

import { provideContext } from '../../../';
import { provideContext, FluxibleContext } from '../../../';

describe('fluxible-addons-react', () => {
describe('provideContext', () => {
Expand Down Expand Up @@ -53,30 +53,25 @@ describe('fluxible-addons-react', () => {
});

it('should provide the context with custom types to children', () => {
const plugins = ['foo'];
const context = {
foo: 'bar',
executeAction: function() {},
getStore: function() {}
};

class Component extends React.Component {
static contextTypes = {
foo: PropTypes.string.isRequired,
executeAction: PropTypes.func.isRequired,
getStore: PropTypes.func.isRequired
}
static contextType = FluxibleContext;

render() {
expect(this.context.foo).to.equal(context.foo);
expect(this.context.executeAction).to.equal(context.executeAction);
expect(this.context.getStore).to.equal(context.getStore);
expect(this.context.foo).to.equal(context.foo);
return null;
}
}

const WrappedComponent = provideContext(Component, {
foo: PropTypes.string
});
const WrappedComponent = provideContext(Component, plugins);

renderToString(<WrappedComponent context={context} />);
});
Expand Down
13 changes: 4 additions & 9 deletions packages/fluxible-router/src/lib/createNavLinkComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
'use strict';
var React = require('react');
var PropTypes = require('prop-types');
var { FluxibleContext } = require('fluxible-addons-react');
var RouteStore = require('./RouteStore');
var debug = require('debug')('NavLink');
var navigateAction = require('./navigateAction');
Expand Down Expand Up @@ -255,8 +256,7 @@ class NavLink extends React.Component {
try {
onBeforeUnloadText = window.onbeforeunload();
} catch(error) {
var logWarn = (this.context.logger && this.context.logger.warn) || console.warn;
logWarn('Warning: Call of window.onbeforeunload failed', error);
console.warn('Warning: Call of window.onbeforeunload failed', error);
}
}
var confirmResult = onBeforeUnloadText ? window.confirm(onBeforeUnloadText) : true;
Expand Down Expand Up @@ -291,8 +291,7 @@ class NavLink extends React.Component {
throw new Error('NavLink created with empty or missing href \'' + props.href +
'\'or unresolvable routeName \'' + props.routeName);
} else {
var logError = (this.context.logger && this.context.logger.error) || console.error;
logError('Error: Render NavLink with empty or missing href', props);
console.error('Error: Render NavLink with empty or missing href', props);
}
}

Expand Down Expand Up @@ -361,11 +360,7 @@ class NavLink extends React.Component {
NavLink._isMounted = false;
NavLink.autobind = false;
NavLink.displayName = 'NavLink';
NavLink.contextTypes = {
executeAction: PropTypes.func.isRequired,
getStore: PropTypes.func.isRequired,
logger: PropTypes.object
}
NavLink.contextType = FluxibleContext;
NavLink.propTypes = {
href: PropTypes.string,
stopPropagation: PropTypes.bool,
Expand Down
9 changes: 3 additions & 6 deletions packages/fluxible-router/src/lib/handleHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
var React = require('react');
var PropTypes = require('prop-types');
var debug = require('debug')('FluxibleRouter:handleHistory');
var { FluxibleContext } = require('fluxible-addons-react');
var handleRoute = require('../lib/handleRoute');
var navigateAction = require('../lib/navigateAction');
var History = require('./History');
Expand Down Expand Up @@ -59,10 +60,7 @@ function createComponent(Component, opts) {
inherits(HistoryHandler, React.Component);

HistoryHandler.displayName = 'HistoryHandler';
HistoryHandler.contextTypes = {
executeAction: PropTypes.func.isRequired,
logger: PropTypes.object
};
HistoryHandler.contextType = FluxibleContext;
HistoryHandler.propTypes = {
currentRoute: PropTypes.object,
currentNavigate: PropTypes.object
Expand Down Expand Up @@ -168,8 +166,7 @@ function createComponent(Component, opts) {
try {
onBeforeUnloadText = window.onbeforeunload();
} catch(error) {
var logWarn = (this.context.logger && this.context.logger.warn) || console.warn;
logWarn('Warning: Call of window.onbeforeunload failed', error);
console.warn('Warning: Call of window.onbeforeunload failed', error);
}
}
var confirmResult = onBeforeUnloadText ? window.confirm(onBeforeUnloadText) : true;
Expand Down
6 changes: 2 additions & 4 deletions packages/fluxible-router/src/lib/handleRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
'use strict';
var React = require('react');
var PropTypes = require('prop-types');
var connectToStores = require('fluxible-addons-react').connectToStores;
var { connectToStores, FluxibleContext } = require('fluxible-addons-react');
var hoistNonReactStatics = require('hoist-non-react-statics');
var inherits = require('inherits');

Expand All @@ -19,9 +19,7 @@ function createComponent(Component) {
inherits(RouteHandler, React.Component);

RouteHandler.displayName = 'RouteHandler';
RouteHandler.contextTypes = {
getStore: PropTypes.func.isRequired
};
RouteHandler.contextType = FluxibleContext;
RouteHandler.propTypes = {
currentRoute: PropTypes.object,
currentNavigate: PropTypes.object,
Expand Down
Loading