Add MobX for state management

This commit is contained in:
Jan Tuomi
2018-06-20 12:54:44 +03:00
parent 71dbb2b58c
commit 04d6bd032a
12 changed files with 195 additions and 59 deletions
+20 -2
View File
@@ -7960,8 +7960,7 @@
"hoist-non-react-statics": { "hoist-non-react-statics": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz",
"integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w==", "integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
"dev": true
}, },
"home-or-tmp": { "home-or-tmp": {
"version": "2.0.0", "version": "2.0.0",
@@ -12224,6 +12223,20 @@
"minimist": "0.0.8" "minimist": "0.0.8"
} }
}, },
"mobx": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/mobx/-/mobx-5.0.3.tgz",
"integrity": "sha1-U7l/Kg+bDdd3TJYkn4G/LVE9jhw="
},
"mobx-react": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.3.tgz",
"integrity": "sha512-OuSlF2nJEa1PGookZcZnINbvEK4iWNNYiqUh6aebk2AkWxj3sG8OafDOQMcMYApQALTHRsrBIjOx/K8TFxcz7w==",
"requires": {
"hoist-non-react-statics": "^2.5.0",
"react-lifecycles-compat": "^3.0.2"
}
},
"moment": { "moment": {
"version": "2.22.2", "version": "2.22.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
@@ -15694,6 +15707,11 @@
} }
} }
}, },
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"read-all-stream": { "read-all-stream": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
+6 -3
View File
@@ -19,8 +19,8 @@
"build": "npm run clean-dist && webpack -p --config=configs/webpack/prod.js", "build": "npm run clean-dist && webpack -p --config=configs/webpack/prod.js",
"clean-dist": "rm -f -r -d dist", "clean-dist": "rm -f -r -d dist",
"lint": "npm run lint:ts && npm run lint:sass", "lint": "npm run lint:ts && npm run lint:sass",
"lint:ts": "tslint './src/**/*.ts*' --format stylish --force", "lint:ts": "tslint './src/**/**/*.ts*' './src/**/*.ts*' './src/*.ts*' './*.ts*' --format stylish --force",
"lint:sass": "stylelint ./src/**/*.scss", "lint:sass": "stylelint ./src/**/**/*.scss ./src/**/*.scss ./src/*.scss",
"start": "npm run start-dev", "start": "npm run start-dev",
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js", "start-dev": "webpack-dev-server --config=configs/webpack/dev.js",
"test": "npm-run-all test:unit test:e2e", "test": "npm-run-all test:unit test:e2e",
@@ -72,6 +72,9 @@
"webpack-dev-server": "^3.1.4", "webpack-dev-server": "^3.1.4",
"webpack-merge": "^4.1.2" "webpack-merge": "^4.1.2"
}, },
"dependencies": {}, "dependencies": {
"mobx": "^5.0.3",
"mobx-react": "^5.2.3"
},
"postcss": {} "postcss": {}
} }
+19 -9
View File
@@ -1,14 +1,24 @@
import * as React from 'react'; import * as React from "react";
import './{{ properCase name}}.scss'; {{#if observer}}
import { observer } from "mobx-react";
import {{ camelCase store_name }} from "../../stores/{{ properCase store_name }}";
{{/if}}
import "./{{ properCase name}}.scss";
export interface {{ properCase name }}Props {} export interface {{ properCase name }}Props {}
export default class {{ properCase name }} extends React.Component<{{ properCase name }}Props, undefined> { {{#if observer}}@observer{{/if}} class {{ properCase name }} extends React.Component<{{ properCase name }}Props, undefined> {
render() { render() {
return ( return (
<div className="{{ dashCase name }}"> <div className="{{ dashCase name }}">
{{ titleCase name }} {{ titleCase name }}
</div> </div>
); );
} }
} }
{{#if observer}}
export default (props) => <{{ properCase name }} {{ camelCase store_name }}={ {{ camelCase store_name }} } { ...props } />;
{{else}}
export default <{{ properCase name }} />;
{{/if}}
+2 -2
View File
@@ -1,2 +1,2 @@
import {{ properCase name }} from './{{ properCase name }}'; import {{ properCase name }} from "./{{ properCase name }}";
export default {{ properCase name }}; export default {{ properCase name }};
+13
View File
@@ -0,0 +1,13 @@
import { observable, action } from "mobx";
import { observer } from "mobx-react";
class {{ properCase name }} {
@observable counter = 0;
@action.bound
increment() {
this.counter += 1;
}
}
export default new {{ properCase name }}();
+61 -31
View File
@@ -1,33 +1,63 @@
module.exports = function(plop) { module.exports = function(plop) {
// create your generators here // create your generators here
plop.setGenerator('New component', { plop.setGenerator("New component", {
description: 'Create a new TSX + SCSS component for React.', description: "Create a new TSX + SCSS component for React.",
prompts: [ prompts: [
{ {
type: 'input', type: "input",
name: 'name', name: "name",
message: 'Component name' message: "Component name:"
} },
], // array of inquirer prompts {
actions: [ type: "list",
{ choices: [{ name: "No, it does not observe a store", value: false }, { name: "Yes, it observes a store", value: true }],
type: 'add', name: "observer",
path: 'src/components/{{ properCase name }}/{{ properCase name }}.tsx', message: "Is the component a MobX observer?"
templateFile: 'plop-templates/component.tsx', },
abortOnFail: true {
}, type: "input",
{ name: "store_name",
type: 'add', message: "MobX store name:",
path: 'src/components/{{ properCase name }}/{{ properCase name }}.scss', when: answers => answers.observer
templateFile: 'plop-templates/component.scss', },
abortOnFail: true ], // array of inquirer prompts
}, actions: [
{ {
type: 'add', type: "add",
path: 'src/components/{{ properCase name }}/index.ts', path: "src/components/{{ properCase name }}/{{ properCase name }}.tsx",
templateFile: 'plop-templates/index.ts', templateFile: "plop-templates/component.tsx",
abortOnFail: true abortOnFail: true
} },
] // array of actions {
}); type: "add",
path: "src/components/{{ properCase name }}/{{ properCase name }}.scss",
templateFile: "plop-templates/component.scss",
abortOnFail: true
},
{
type: "add",
path: "src/components/{{ properCase name }}/index.ts",
templateFile: "plop-templates/index.ts",
abortOnFail: true
}
] // array of actions
});
plop.setGenerator("New MobX state store", {
description: "Create a new store for MobX.",
prompts: [
{
type: "input",
name: "name",
message: "Store name:"
}
], // array of inquirer prompts
actions: [
{
type: "add",
path: "src/stores/{{ properCase name }}.ts",
templateFile: "plop-templates/store.ts",
abortOnFail: true
}
] // array of actions
});
}; };
+21 -11
View File
@@ -1,18 +1,28 @@
import * as React from "react"; import * as React from "react";
import { observer } from "mobx-react";
import "./App.scss"; import "./App.scss";
import appState from "../../stores/AppStore";
const reactLogo = require("../../assets/img/react_logo.svg"); import Button from "../Button";
export interface AppProps { export interface AppProps {
appState: {
increment: () => string,
counter: number
};
} }
export default class App extends React.Component<AppProps, undefined> { @observer class App extends React.Component<AppProps, undefined> {
render() { constructor(props) {
return ( super(props);
<div className="app__landing"> }
<h1>Aalto-yliopiston sähköinsinöörikilta!</h1>
<p>Sähköä, viinaa, naisia.</p> render() {
</div> return <div className="app__landing">
); <h1>Aalto-yliopiston sähköinsinöörikilta!</h1>
} <p>Sähköä, viinaa, naisia.</p>
<Button onClick={this.props.appState.increment}>{this.props.appState.counter}</Button>
</div>;
}
} }
export default props => <App appState={appState} {...props} />;
+20
View File
@@ -0,0 +1,20 @@
@import "../../index.scss";
.button {
-webkit-appearance: none;
border-radius: none;
padding: 0.5rem 1rem;
margin: 0.5rem;
border: 2px solid $blue;
font-size: 1rem;
font-weight: 500;
&:hover {
border: 2px solid $dark-blue;
}
&:active,
&:focus {
outline: none;
}
}
+16
View File
@@ -0,0 +1,16 @@
import * as React from "react";
import "./Button.scss";
export interface ButtonProps {
onClick: () => void;
}
export default class Button extends React.Component<ButtonProps, undefined> {
render() {
return (
<button onClick={this.props.onClick} className="button">
{this.props.children}
</button>
);
}
}
+2
View File
@@ -0,0 +1,2 @@
import Button from "./Button";
export default Button;
+13
View File
@@ -0,0 +1,13 @@
import { observable, action } from "mobx";
import { observer } from "mobx-react";
class AppStore {
@observable counter = 0;
@action.bound
increment() {
this.counter += 1;
}
}
export default new AppStore();
+2 -1
View File
@@ -6,7 +6,8 @@
"module": "commonjs", "module": "commonjs",
"target": "es5", "target": "es5",
"jsx": "react", "jsx": "react",
"lib": ["es5", "es6", "dom"] "lib": ["es5", "es6", "dom"],
"experimentalDecorators": true
}, },
"include": [ "include": [
"./src/**/*" "./src/**/*"