Skip to content

Commit

Permalink
Merge 1ad2505 into 7cefde7
Browse files Browse the repository at this point in the history
  • Loading branch information
julienben committed Apr 14, 2019
2 parents 7cefde7 + 1ad2505 commit 130b637
Show file tree
Hide file tree
Showing 21 changed files with 331 additions and 374 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Now you're ready to rumble!
## Documentation

- [**The Hitchhikers Guide to `react-boilerplate`**](docs/general/introduction.md): An introduction for newcomers to this boilerplate.
- [**The Hitchhiker's Guide to `react-boilerplate`**](docs/general/introduction.md): An introduction for newcomers to this boilerplate.
- [Overview](docs/general): A short overview of the included tools
- [**Commands**](docs/general/commands.md): Getting the most out of this boilerplate
- [Testing](docs/testing): How to work with the built-in test harness
Expand Down
14 changes: 7 additions & 7 deletions app/containers/HomePage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ HomePage.propTypes = {
onChangeUsername: PropTypes.func,
};

const mapStateToProps = createStructuredSelector({
repos: makeSelectRepos(),
username: makeSelectUsername(),
loading: makeSelectLoading(),
error: makeSelectError(),
});

export function mapDispatchToProps(dispatch) {
return {
onChangeUsername: evt => dispatch(changeUsername(evt.target.value)),
Expand All @@ -120,13 +127,6 @@ export function mapDispatchToProps(dispatch) {
};
}

const mapStateToProps = createStructuredSelector({
repos: makeSelectRepos(),
username: makeSelectUsername(),
loading: makeSelectLoading(),
error: makeSelectError(),
});

const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
Expand Down
32 changes: 31 additions & 1 deletion app/utils/tests/injectReducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { memoryHistory } from 'react-router-dom';
import React from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import { render } from 'react-testing-library';

import configureStore from '../../configureStore';
import injectReducer from '../injectReducer';
import injectReducer, { useInjectReducer } from '../injectReducer';
import * as reducerInjectors from '../reducerInjectors';

// Fixtures
Expand Down Expand Up @@ -66,3 +67,32 @@ describe('injectReducer decorator', () => {
expect(children.props).toEqual(props);
});
});

describe('useInjectReducer hook', () => {
let store;
let injectors;
let ComponentWithReducer;

beforeAll(() => {
injectors = {
injectReducer: jest.fn(),
};
reducerInjectors.default = jest.fn().mockImplementation(() => injectors);
store = configureStore({}, memoryHistory);
ComponentWithReducer = () => {
useInjectReducer({ key: 'test', reducer });
return null;
};
});

it('should inject a given reducer', () => {
render(
<Provider store={store}>
<ComponentWithReducer />
</Provider>,
);

expect(injectors.injectReducer).toHaveBeenCalledTimes(1);
expect(injectors.injectReducer).toHaveBeenCalledWith('test', reducer);
});
});
58 changes: 57 additions & 1 deletion app/utils/tests/injectSaga.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import { memoryHistory } from 'react-router-dom';
import { put } from 'redux-saga/effects';
import renderer from 'react-test-renderer';
import { render } from 'react-testing-library';
import React from 'react';
import { Provider } from 'react-redux';

import configureStore from '../../configureStore';
import injectSaga from '../injectSaga';
import injectSaga, { useInjectSaga } from '../injectSaga';
import * as sagaInjectors from '../sagaInjectors';

// Fixtures
Expand Down Expand Up @@ -91,3 +92,58 @@ describe('injectSaga decorator', () => {
expect(children.props).toEqual(props);
});
});

describe('useInjectSaga hook', () => {
let store;
let injectors;
let ComponentWithSaga;

beforeAll(() => {
sagaInjectors.default = jest.fn().mockImplementation(() => injectors);
});

beforeEach(() => {
store = configureStore({}, memoryHistory);
injectors = {
injectSaga: jest.fn(),
ejectSaga: jest.fn(),
};
ComponentWithSaga = () => {
useInjectSaga({
key: 'test',
saga: testSaga,
mode: 'testMode',
});
return null;
};
sagaInjectors.default.mockClear();
});

it('should inject given saga and mode', () => {
const props = { test: 'test' };
render(
<Provider store={store}>
<ComponentWithSaga {...props} />
</Provider>,
);

expect(injectors.injectSaga).toHaveBeenCalledTimes(1);
expect(injectors.injectSaga).toHaveBeenCalledWith('test', {
saga: testSaga,
mode: 'testMode',
});
});

it('should eject on unmount with a correct saga key', () => {
const props = { test: 'test' };
const renderedComponent = renderer.create(
<Provider store={store}>
<ComponentWithSaga {...props} />
</Provider>,
);
renderedComponent.unmount();

expect(injectors.ejectSaga).toHaveBeenCalledTimes(1);
expect(injectors.ejectSaga).toHaveBeenCalledWith('test');
});
});
60 changes: 28 additions & 32 deletions docs/css/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
# Styling (CSS)

## Table of Contents

- [Next Generation CSS](#next-generation-css)
- [CSS Support](#css-we-support)
- [Linting](#linting)
- [sanitize.css](#sanitizecss)
- [CSS Support](#css-support)
- [styled-components](#styled-components)
- [Stylesheet](#stylesheet)
- [CSS Modules](#css-modules)
- [Setup](#setup)
- [Usage](#usage)
- [Sass](#sass)
- [Setup](#setup-1)
- [Usage](#usage-1)
- [LESS](#less)
- [Setup](#setup-2)
- [Usage](#usage-2)

## Next Generation CSS

Expand Down Expand Up @@ -70,17 +76,15 @@ const Wrapper = styled.section`
`;

// Use them like any other React component – except they're styled!
class Button extends React.Component {
render() {
return (
<Wrapper>
<Title>
Hello {this.props.name}, this is your first styled component!
</Title>
...
</Wrapper>
);
}
function Button() {
return (
<Wrapper>
<Title>
Hello {this.props.name}, this is your first styled component!
</Title>
...
</Wrapper>
);
}
```

Expand Down Expand Up @@ -108,11 +112,9 @@ into a JavaScript:
import React from 'react';
import './Button.css'; // Tell Webpack that Button.js uses these styles

class Button extends React.Component {
render() {
// You can use them as regular CSS styles
return <button className="danger">Click me</button>;
}
function Button() {
// You can use them as regular CSS styles
return <button className="danger">Click me</button>;
}
```

Expand Down Expand Up @@ -162,11 +164,9 @@ The key difference in CSS Modules is that you import styles to a variable.
import React from 'react';
import styles from './Button.css'; // different import compared to stylesheets

class Button extends React.Component {
render() {
// different usage to stylesheets
return <button className={styles.danger}>Click me</button>;
}
function Button() {
// different usage to stylesheets
return <button className={styles.danger}>Click me</button>;
}
```

Expand Down Expand Up @@ -216,10 +216,8 @@ $error-color: red;
import React from 'react';
import './Button.scss';

class Button extends React.Component {
render() {
return <button className="danger">Click me</button>;
}
function Button() {
return <button className="danger">Click me</button>;
}
```

Expand Down Expand Up @@ -275,10 +273,8 @@ to look like:
import React from 'react';
import './Button.less';

class Button extends React.Component {
render() {
return <button className="danger">Click me</button>;
}
function Button() {
return <button className="danger">Click me</button>;
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/general/introduction.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# The Hitchhikers Guide to `react-boilerplate`
# The Hitchhiker's Guide to `react-boilerplate`

The [`README.md`](https://github.com/react-boilerplate/react-boilerplate#features) gives you adequate information on how to clone boilerplate files, install dependencies and launch the example app.

Expand Down Expand Up @@ -35,8 +35,8 @@ Here's a curated list of packages that you should be at least familiar with befo

Note that while `react-boilerplate` includes a lot of features, many of them are optional and you can find instructions in the docs on how to remove...

- [...`redux-saga` or `reselect`](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/js/remove.md).
- ...[offline-first, add to homescreen, performant web font loading and image optimisation](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/general/remove.md)
- [`redux-saga` or `reselect`](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/js/remove.md)
- [offline-first, add to homescreen, performant web font loading and image optimisation](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/general/remove.md)
- [`sanitize.css`](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/css/remove.md)
- [i18n (i.e. `react-intl`)](https://github.com/react-boilerplate/react-boilerplate/blob/0f88f55ed905f8432c3dd7b452d713df5fb76d8e/docs/js/i18n.md#removing-i18n-and-react-intl)

Expand Down
22 changes: 7 additions & 15 deletions docs/js/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ for more information)

## Usage

To add a new route, simply import the `Route` component and use it standalone or inside the `Switch` component (all part of [RR4 API](https://reacttraining.com/react-router/web/api)):
To add a new route, simply import the `Route` component and use it standalone or inside the `Switch` component (all part of [RR5 API](https://reacttraining.com/react-router/web/api)):

```JS
<Route exact path="/" component={HomePage} />
Expand Down Expand Up @@ -48,21 +48,13 @@ in `App.js` to create a `Switch` within the parent component. Also remove the `e
// AboutPage/index.js
import { Switch, Route } from 'react-router-dom';

class AboutPage extends React.PureComponent {
render() {
return (
<Switch>
<Route exact path="/about/our-team" />
</Switch>
);
}
function AboutPage() {
return (
<Switch>
<Route exact path="/about/our-team" />
</Switch>
);
}
```

Note that with React Router v4, route re-rendering is handled by React's `setState`. This
means that when wrapping route components in a redux connected container, or `PureComponent` or any other component with
`shouldComponentUpdate`, you need to create a [ConnectedSwitch](https://github.com/ReactTraining/react-router/issues/5072#issuecomment-310184271)
container that receives `location` directly from a redux store. Read more about this in
[Dealing with Update Blocking](https://reacttraining.com/react-router/web/guides/dealing-with-update-blocking).

You can read more in [`react-router`'s documentation](https://reacttraining.com/react-router/web/api).
6 changes: 2 additions & 4 deletions docs/testing/component-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ It might be used in another component like this:

import Button from './Button';

class HomePage extends React.Component {
render() {
return <Button onClick={this.doSomething}>Click me!</Button>;
}
function HomePage() {
return <Button onClick={this.doSomething}>Click me!</Button>;
}
```

Expand Down
31 changes: 0 additions & 31 deletions internals/generators/component/class.js.hbs

This file was deleted.

0 comments on commit 130b637

Please sign in to comment.