Skip to content

Commit

Permalink
feat(package): fixes to support React.StrictMode (#512)
Browse files Browse the repository at this point in the history
  • Loading branch information
wallzero authored and christopherthielen committed Sep 4, 2019
1 parent 0f4a233 commit cd8777a
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 75 deletions.
26 changes: 14 additions & 12 deletions examples/typescript/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,19 @@ const routerConfig = (router: UIRouterReact) => {

let el = document.getElementById('react-app');
let app = (
<UIRouter plugins={[pushStateLocationPlugin]} states={[home, child, nest]} config={routerConfig}>
<div>
<UISrefActive class="active">
<UISref to="home">
<a>Home</a>
</UISref>
</UISrefActive>
<UIView render={(Comp, props) => <Comp {...props} foo="bar" />}>
<p>Content will load here</p>
</UIView>
</div>
</UIRouter>
<React.StrictMode>
<UIRouter plugins={[pushStateLocationPlugin]} states={[home, child, nest]} config={routerConfig}>
<div>
<UISrefActive class="active">
<UISref to="home">
<a>Home</a>
</UISref>
</UISrefActive>
<UIView render={(Comp, props) => <Comp {...props} foo="bar" />}>
<p>Content will load here</p>
</UIView>
</div>
</UIRouter>
</React.StrictMode>
);
ReactDOM.render(app, el);
2 changes: 1 addition & 1 deletion examples/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
"tsconfig-paths-webpack-plugin": "^3.0.4",
"typescript": "2.8.3",
"webpack": "^4.7.0",
"webpack-dev-server": "^3.1.4"
"webpack-dev-server": "3.7.1"
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"react": "^16.5.1",
"react-dom": "^16.5.1",
"react-test-renderer": "^16.5.1",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"ts-jest": "^23.1.3",
"ts-loader": "^6.0.2",
"typescript": "^3.0.1",
Expand All @@ -96,7 +97,7 @@
"testRegex": "/__tests__/.*\\.(ts|tsx|js)$",
"globals": {
"ts-jest": {
"tsConfigFile": "../tsconfig.jest.json"
"tsConfigFile": "./tsconfig.jest.json"
}
}
},
Expand Down
67 changes: 35 additions & 32 deletions src/components/UIRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
* @module components
*/ /** */
import * as React from 'react';
import { Component, Children } from 'react';
import { Component } from 'react';
import * as PropTypes from 'prop-types';

import { UIRouterPlugin, servicesPlugin } from '@uirouter/core';
import { servicesPlugin } from '@uirouter/core';

import { UIRouterReact, ReactStateDeclaration } from '../index';

Expand Down Expand Up @@ -44,21 +44,21 @@ export interface UIRouterState {

/** @hidden */
export const InstanceOrPluginsMissingError = new Error(`Router instance or plugins missing.
You must either provide a location plugin via the plugins prop:
<UIRouter plugins={[pushStateLocationPlugin]} states={[···]}>
<UIView />
</UIRouter>
or initialize the router yourself and pass the instance via props:
const router = new UIRouterReact();
router.plugin(pushStateLocationPlugin);
···
<UIRouter router={router}>
<UIView />
</UIRouter>
`);
You must either provide a location plugin via the plugins prop:
<UIRouter plugins={[pushStateLocationPlugin]} states={[···]}>
<UIView />
</UIRouter>
or initialize the router yourself and pass the instance via props:
const router = new UIRouterReact();
router.plugin(pushStateLocationPlugin);
···
<UIRouter router={router}>
<UIView />
</UIRouter>
`);

/** @hidden */
export const UIRouterInstanceUndefinedError = new Error(
Expand All @@ -76,24 +76,27 @@ export class UIRouter extends Component<UIRouterProps, UIRouterState> {

router: UIRouterReact;

constructor(props, context) {
super(props, context);
// check if a router instance is provided
if (props.router) {
this.router = props.router;
} else if (props.plugins) {
this.router = new UIRouterReact();
this.router.plugin(servicesPlugin);
props.plugins.forEach(plugin => this.router.plugin(plugin));
if (props.config) props.config(this.router);
(props.states || []).forEach(state => this.router.stateRegistry.register(state));
} else {
throw InstanceOrPluginsMissingError;
componentDidMount() {
if (!this.router) {
// check if a router instance is provided
if (this.props.router) {
this.router = this.props.router;
} else if (this.props.plugins) {
this.router = new UIRouterReact();
this.router.plugin(servicesPlugin);
this.props.plugins.forEach(plugin => this.router.plugin(plugin));
if (this.props.config) this.props.config(this.router);
(this.props.states || []).forEach(state => this.router.stateRegistry.register(state));
} else {
throw InstanceOrPluginsMissingError;
}

this.router.start();
this.forceUpdate();
}
this.router.start();
}

render() {
return <UIRouterProvider value={this.router}>{this.props.children}</UIRouterProvider>;
return this.router ? <UIRouterProvider value={this.router}>{this.props.children}</UIRouterProvider> : null;
}
}
6 changes: 4 additions & 2 deletions src/components/UISref.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Sref extends Component<SrefProps, any> {
className: PropTypes.string,
};

componentWillMount() {
componentDidMount() {
const addStateInfo = this.props.addStateInfoToParentActive;
this.deregister = typeof addStateInfo === 'function' ? addStateInfo(this.props.to, this.props.params) : () => {};
const router = this.props.router;
Expand All @@ -54,7 +54,9 @@ class Sref extends Component<SrefProps, any> {
}

componentWillUnmount() {
this.deregister();
if (this.deregister) {
this.deregister();
}
}

getOptions = () => {
Expand Down
10 changes: 6 additions & 4 deletions src/components/UISrefActive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* @module components
*/ /** */
import * as React from 'react';
import { Component, cloneElement, ValidationMap } from 'react';
import { Component, cloneElement } from 'react';
import * as PropTypes from 'prop-types';
import * as _classNames from 'classnames';

import { UIRouterReact, UISref, UIRouterConsumer } from '../index';
import { UIRouterReact, UIRouterConsumer } from '../index';
import { UIViewAddress } from './UIView';
import { UIRouterInstanceUndefinedError } from './UIRouter';

Expand Down Expand Up @@ -59,7 +59,7 @@ class SrefActive extends Component<UISrefActiveProps, any> {
activeClasses: '',
};

componentWillMount() {
componentDidMount() {
const router = this.props.router;
if (typeof router === 'undefined') {
throw UIRouterInstanceUndefinedError;
Expand All @@ -69,7 +69,9 @@ class SrefActive extends Component<UISrefActiveProps, any> {
}

componentWillUnmount() {
this.deregister();
if (this.deregister) {
this.deregister();
}
}

addStateInfo = (stateName, stateParams) => {
Expand Down
26 changes: 20 additions & 6 deletions src/components/UIView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import {
ClassicComponentClass,
Component,
ComponentClass,
createContext,
SFC,
ReactNode,
StatelessComponent,
ValidationMap,
Validator,
cloneElement,
createElement,
isValidElement,
isValidElement
} from 'react';
import * as PropTypes from 'prop-types';

Expand Down Expand Up @@ -78,6 +80,7 @@ export interface UIViewInjectedProps {

/** Component Props for `UIView` */
export interface UIViewProps {
children?: ReactNode;
router?: UIRouterReact;
parentUIView?: UIViewAddress;
name?: string;
Expand All @@ -100,7 +103,7 @@ export const TransitionPropCollisionError = new Error(
);

/** @internalapi */
export const { Provider: UIViewProvider, Consumer: UIViewConsumer } = React.createContext<UIViewAddress>(undefined);
export const { Provider: UIViewProvider, Consumer: UIViewConsumer } = createContext<UIViewAddress>(undefined);

class View extends Component<UIViewProps, UIViewState> {
// This object contains all the metadata for this UIView
Expand Down Expand Up @@ -168,7 +171,7 @@ class View extends Component<UIViewProps, UIViewState> {
return <UIViewProvider value={this.uiViewAddress}>{ChildOrRenderFunction}</UIViewProvider>;
}

componentWillMount() {
componentDidMount() {
const router = this.props.router;
if (typeof router === 'undefined') {
throw UIRouterInstanceUndefinedError;
Expand Down Expand Up @@ -199,7 +202,9 @@ class View extends Component<UIViewProps, UIViewState> {
}

componentWillUnmount() {
this.deregister();
if (this.deregister) {
this.deregister();
}
}

/**
Expand Down Expand Up @@ -262,9 +267,18 @@ class View extends Component<UIViewProps, UIViewState> {
}
}

export class UIView extends React.Component<UIViewProps, any> {
View.propTypes = {
router: PropTypes.object.isRequired as Validator<UIRouterReact>,
parentUIView: PropTypes.object as Validator<UIViewAddress>,
name: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
render: PropTypes.func,
} as ValidationMap<UIViewProps>;

export class UIView extends Component<UIViewProps, any> {
static displayName = 'UIView';
static __internalViewComponent: React.ComponentClass<UIViewProps> = View;
static __internalViewComponent: ComponentClass<UIViewProps> = View;

render() {
return (
Expand Down
4 changes: 3 additions & 1 deletion src/components/__tests__/UISref.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ describe('<UISref>', () => {
);
await router.stateService.go('state');
wrapper.update();
const stateServiceGoSpy = jest.spyOn(wrapper.instance().router.stateService, 'go');
// @ts-ignore
const stateServiceGoSpy = jest.spyOn(router.stateService, 'go');
const link = wrapper.find('a');
link.simulate('click');
link.simulate('click', { button: 1 });
Expand All @@ -162,6 +163,7 @@ describe('<UISref>', () => {
.find('Sref')
.at(0);
expect(uiSref.instance().context.parentUIViewAddress).toBeUndefined();
// @ts-ignore
expect(uiSref.instance().getOptions().relative.name).toBe('');
});
});
5 changes: 5 additions & 0 deletions src/components/__tests__/UISrefActive.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ describe('<UISrefActive>', () => {
.at(0)
.instance();
expect(instance.context.parentUIViewAddress).toBeUndefined();
// @ts-ignore
expect(instance.states[0].state.name).toBe('parent.child1');
});

Expand Down Expand Up @@ -232,6 +233,7 @@ describe('<UISrefActive>', () => {
.at(0)
.instance();
expect(instance.context.parentUIViewAddress).toBeUndefined();
// @ts-ignore
expect(instance.states.length).toBe(3);
});

Expand Down Expand Up @@ -266,6 +268,7 @@ describe('<UISrefActive>', () => {
.find('SrefActive')
.at(0)
.instance();
// @ts-ignore
expect(instance.states.length).toBe(3);

router.stateRegistry.register({
Expand Down Expand Up @@ -340,8 +343,10 @@ describe('<UISrefActive>', () => {
.find('SrefActive')
.at(0)
.instance();
// @ts-ignore
expect(instance.states.length).toBe(1);
wrapper.setProps({ show: false });
// @ts-ignore
expect(instance.states.length).toBe(0);
});

Expand Down
Loading

0 comments on commit cd8777a

Please sign in to comment.