/@types/index.d.ts
/@types/systemjs/index.d.ts
/webpack/config.js
/tsconfig.json
/package.json
/index.html
/src/index.tsx
/src/index-redux.tsx
Файл /@types/index.d.ts
/// <reference path="../node_modules/ufs-ui/typings/globals/EventListener/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/react-dom/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/react-redux/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/react/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/redux-logger/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/redux-thunk/index.d.ts" />
/// <reference path="../node_modules/ufs-ui/typings/globals/redux/index.d.ts" />
/// <reference path="../node_modules/typings/modules/react-router/index.d.ts" />
// Type definitions for SystemJS 0.19.29
// Project: https://github.com/systemjs/systemjs
// Definitions by: Ludovic HENIN <https://github.com/ludohenin/>, Nathan Walker <https://github.com/NathanWalker/>, Giedrius Grabauskas <https://github.com/GiedriusGrabauskas>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace SystemJSLoader {
type ModulesList = { [bundleName: string]: Array<string> };
type PackageList<T> = { [packageName: string]: T };
/**
* The following module formats are supported:
*
* - esm: ECMAScript Module (previously referred to as es6)
* - cjs: CommonJS
* - amd: Asynchronous Module Definition
* - global: Global shim module format
* - register: System.register or System.registerDynamic compatibility module format
*
*/
type ModuleFormat = "esm" | "cjs" | "amd" | "global" | "register";
/**
* Sets the module name of the transpiler to be used for loading ES6 modules.
* Represents a module name for System.import that must resolve to either Traceur, Babel or TypeScript.
* When set to traceur, babel or typescript, loading will be automatically configured as far as possible.
*/
type Transpiler = "plugin-traceur" | "plugin-babel" | "plugin-typescript" | "traceur" | "babel" | "typescript" | boolean;
type ConfigMap = PackageList<string>;
type ConfigMeta = PackageList<MetaConfig>;
interface MetaConfig {
/**
* Sets in what format the module is loaded.
*/
format?: ModuleFormat;
/**
* For the global format, when automatic detection of exports is not enough, a custom exports meta value can be set.
* This tells the loader what global name to use as the module's export value.
*/
exports?: string;
/**
* Dependencies to load before this module. Goes through regular paths and map normalization.
* Only supported for the cjs, amd and global formats.
*/
deps?: Array<string>;
/**
* A map of global names to module names that should be defined only for the execution of this module.
* Enables use of legacy code that expects certain globals to be present.
* Referenced modules automatically becomes dependencies. Only supported for the cjs and global formats.
*/
globals?: string;
/**
* Set a loader for this meta path.
*/
loader?: string;
/**
* For plugin transpilers to set the source map of their transpilation.
*/
sourceMap?: any;
/**
* Load the module using <script> tag injection.
*/
scriptLoad?: boolean;
/**
* The nonce attribute to use when loading the script as a way to enable CSP.
* This should correspond to the "nonce-" attribute set in the Content-Security-Policy header.
*/
nonce?: string;
/**
* The subresource integrity attribute corresponding to the script integrity,
* describing the expected hash of the final code to be executed.
* For example, System.config({ meta: { 'src/example.js': { integrity: 'sha256-e3b0c44...' }});
* would throw an error if the translated source of src/example.js doesn't match the expected hash.
*/
integrity?: string;
/**
* When scripts are loaded from a different domain (e.g. CDN) the global error handler (window.onerror)
* has very limited information about errors to prevent unintended leaking. In order to mitigate this,
* the <script> tags need to set crossorigin attribute and the server needs to enable CORS.
* The valid values are "anonymous" and "use-credentials".
*/
crossOrigin?: string;
/**
* When loading a module that is not an ECMAScript Module, we set the module as the default export,
* but then also iterate the module object and copy named exports for it a well.
* Use this option to disable this iteration and copying of the exports.
*/
esmExports?: boolean;
/**
* To ignore resources that shouldn't be traced as part of the build.
* Use with the SystemJS Builder. (https://github.com/systemjs/builder#ignore-resources)
*/
build?: boolean;
}
interface PackageConfig {
/**
* The main entry point of the package (so import 'local/package' is equivalent to import 'local/package/index.js')
*/
main?: string;
/**
* The module format of the package. See Module Formats.
*/
format?: ModuleFormat;
/**
* The default extension to add to modules requested within the package. Takes preference over defaultJSExtensions.
* Can be set to defaultExtension: false to optionally opt-out of extension-adding when defaultJSExtensions is enabled.
*/
defaultExtension?: boolean | string;
/**
* Local and relative map configurations scoped to the package. Apply for subpaths as well.
*/
map?: ConfigMap;
/**
* Module meta provides an API for SystemJS to understand how to load modules correctly.
* Package-scoped meta configuration with wildcard support. Modules are subpaths within the package path.
* This also provides an opt-out mechanism for defaultExtension, by adding modules here that should skip extension adding.
*/
meta?: ConfigMeta;
}
interface TraceurOptions {
properTailCalls?: boolean;
symbols?: boolean;
arrayComprehension?: boolean;
asyncFunctions?: boolean;
asyncGenerators?: any;
forOn?: boolean;
generatorComprehension?: boolean;
}
interface Config {
/**
* For custom config names
*/
[customName: string]: any;
/**
* The baseURL provides a special mechanism for loading modules relative to a standard reference URL.
*/
baseURL?: string;
/**
* Set the Babel transpiler options when System.transpiler is set to babel.
*/
//TODO: Import BabelCore.TransformOptions
babelOptions?: any;
/**
* undles allow a collection of modules to be downloaded together as a package whenever any module from that collection is requested.
* Useful for splitting an application into sub-modules for production. Use with the SystemJS Builder.
*/
bundles?: ModulesList;
/**
* Backwards-compatibility mode for the loader to automatically add '.js' extensions when not present to module requests.
* This allows code written for SystemJS 0.16 or less to work easily in the latest version:
*/
defaultJSExtensions?: boolean;
/**
* An alternative to bundling providing a solution to the latency issue of progressively loading dependencies.
* When a module specified in depCache is loaded, asynchronous loading of its pre-cached dependency list begins in parallel.
*/
depCache?: ModulesList;
/**
* The map option is similar to paths, but acts very early in the normalization process.
* It allows you to map a module alias to a location or package:
*/
map?: ConfigMap;
/**
* Module meta provides an API for SystemJS to understand how to load modules correctly.
* Meta is how we set the module format of a module, or know how to shim dependencies of a global script.
*/
meta?: ConfigMeta;
/**
* Packages provide a convenience for setting meta and map configuration that is specific to a common path.
* In addition packages allow for setting contextual map configuration which only applies within the package itself.
* This allows for full dependency encapsulation without always needing to have all dependencies in a global namespace.
*/
packages?: PackageList<PackageConfig>;
/**
* The ES6 Module Loader paths implementation, applied after normalization and supporting subpaths via wildcards.
* It is usually advisable to use map configuration over paths unless you need strict control over normalized module names.
*/
paths?: PackageList<string>;
/**
* Set the Traceur compilation options.
*/
traceurOptions?: TraceurOptions;
/**
* Sets the module name of the transpiler to be used for loading ES6 modules.
*/
transpiler?: Transpiler;
trace?: boolean;
/**
* Sets the TypeScript transpiler options.
*/
//TODO: Import Typescript.CompilerOptions
typescriptOptions?: any;
}
interface SystemJSSystemFields {
env: string;
loaderErrorStack: boolean;
packageConfigPaths: Array<string>;
pluginFirst: boolean;
version: string;
warnings: boolean;
}
interface System extends Config, SystemJSSystemFields {
/**
* For backwards-compatibility with AMD environments, set window.define = System.amdDefine.
*/
amdDefine: Function;
/**
* For backwards-compatibility with AMD environments, set window.require = System.amdRequire.
*/
amdRequire: Function;
/**
* SystemJS configuration helper function.
* Once SystemJS has loaded, configuration can be set on SystemJS by using the configuration function System.config.
*/
config(config: Config): void;
/**
* This represents the System base class, which can be extended or reinstantiated to create a custom System instance.
*/
constructor(): System;
/**
* Deletes a module from the registry by normalized name.
*/
delete(moduleName: string): void;
/**
* Returns a module from the registry by normalized name.
*/
get(moduleName: string): any;
get<TModule>(moduleName: string): TModule;
/**
* Returns whether a given module exists in the registry by normalized module name.
*/
has(moduleName: string): boolean;
/**
* Loads a module by name taking an optional normalized parent name argument.
* Promise resolves to the module value.
*/
import(moduleName: string, normalizedParentName?: string): Promise<any>;
import<TModule>(moduleName: string, normalizedParentName?: string): Promise<TModule>;
/**
* Given a plain JavaScript object, return an equivalent Module object.
* Useful when writing a custom instantiate hook or using System.set.
*/
newModule(object: any): any;
newModule<TModule>(object: any): TModule;
/**
* Declaration function for defining modules of the System.register polyfill module format.
*/
register(name: string, deps: Array<string>, declare: Function): void;
register(deps: Array<string>, declare: Function): void;
/**
* Companion module format to System.register for non-ES6 modules.
* Provides a <script>-injection-compatible module format that any CommonJS or Global module can be converted into for CSP compatibility.
*/
registerDynamic(name: string, deps: Array<string>, executingRequire: boolean, declare: Function): void;
registerDynamic(deps: Array<string>, executingRequire: boolean, declare: Function): void;
/**
* Sets a module into the registry directly and synchronously.
* Typically used along with System.newModule to create a valid Module object:
*/
set(moduleName: string, module: any): void;
/**
* In CommonJS environments, SystemJS will substitute the global require as needed by the module format being
* loaded to ensure the correct detection paths in loaded code.
* The CommonJS require can be recovered within these modules from System._nodeRequire.
*/
_nodeRequire: Function;
/**
* Modules list available only with trace=true
*/
loads: PackageList<any>;
}
}
declare var SystemJS: SystemJSLoader.System;
/**
* @deprecated use SystemJS https://github.com/systemjs/systemjs/releases/tag/0.19.10
*/
declare var System: SystemJSLoader.System;
declare module "systemjs" {
import systemJSLoader = SystemJSLoader;
let system: systemJSLoader.System;
export = system;
}
'use strict';
const path = require('path');
const webpack = require('webpack');
const failPlugin = require('webpack-fail-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const precss = require('precss');
const autoprefixer = require('autoprefixer');
const OUTPUT_PATH = 'dist';
let hotEntries = [
'webpack/hot/dev-server'
];
let entry = {
'index': [].concat(hotEntries, path.resolve(__dirname, '../src/index-redux.tsx'))
};
let plugins = [
failPlugin,
new webpack.DefinePlugin({
'buildEnv': JSON.stringify(process.env.NODE_ENV)
})
];
plugins = plugins.concat([
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin([OUTPUT_PATH], {
root: path.resolve(__dirname, '../'),
verbose: false
}),
new CopyWebpackPlugin([
{from: 'index.html'},
// Зависимости
{from: 'node_modules/systemjs/dist/system.js'},
{from: 'node_modules/systemjs/dist/system-polyfills.js'},
{from: 'node_modules/systemjs/dist/system-polyfills.js.map'},
{from: 'node_modules/systemjs/dist/system.js.map'}
])
]);
module.exports = {
context: path.resolve(__dirname, '../'),
entry: entry,
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../' + OUTPUT_PATH),
libraryTarget: 'umd'
},
module: {
loaders: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loaders: ['react-hot-loader/webpack', 'es3ify', 'ts']
},
{
test: /\.s?css$/,
loaders: ['style', 'css', 'postcss']
},
{test: /\.json$/, loader: 'json'},
{test: /\.svg|ico|png|gif|jpg($|\?)/, loader: 'file?name=images/[hash].[ext]'},
{test: /\.eot|ttf|woff|woff2($|\?)/, loader: 'file?name=fonts/[hash].[ext]'}
]
},
postcss: function () {
return [precss, autoprefixer];
},
ts: {
compilerOptions: {
noEmit: false
}
},
resolve: {
root: [
path.resolve(__dirname, '../src')
],
extensions: ['', '.js', '.ts', '.tsx', '.css', '.scss', '.png']
},
plugins: plugins,
devServer: {
contentBase: './' + OUTPUT_PATH,
hot: true,
inline: true,
noInfo: false,
stats: {
hash: false,
version: false,
chunks: false,
publicPath: false,
errors: true,
warnings: true,
children: false
}
}
};
Файл /tsconfig.json
{
"compilerOptions": {
"lib": ["DOM","ES6","ScriptHost"],
"target": "es5",
"noImplicitAny": false,
"sourceMap": true,
"typeRoots": ["./@types"],
"types": ["systemjs"],
"jsx": "react"
},
"files": [
"@types/index.d.ts"
]
}
{
"name": "test",
"version": "1.0.0",
"description": "Test",
"scripts": {
"start": "webpack-dev-server --config webpack/config.js --host localhost --port 8080 --inline --colors"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "0.23.1",
"es3ify-loader": "0.2.0",
"extract-text-webpack-plugin": "1.0.1",
"file-loader": "0.8.5",
"json-loader": "^0.5.4",
"postcss-loader": "^1.1.1",
"postcss-scss": "^0.3.1",
"precss": "1.4.0",
"react-addons-test-utils": "0.14.0",
"react-hot-loader": "3.0.0-beta.6",
"source-map-loader": "0.1.5",
"style-loader": "0.13.1",
"ts-loader": "0.8.2",
"typescript": "2.2.1",
"url-loader": "0.5.7",
"webpack": "1.14.0",
"webpack-dev-server": "1.16.2",
"webpack-fail-plugin": "1.0.4",
"zip-folder": "^1.0.0"
},
"dependencies": {
"core-js": "1.2.7",
"es6-promise": "3.0.2",
"react": "0.14.0",
"react-dom": "0.14.0",
"redux": "3.6.0",
"react-redux": "5.0.5",
"redux-logger": "3.0.6",
"redux-thunk": "2.2.0",
"systemjs": "0.19.35"
}
}
Файл /index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="index.bundle.js" charset="utf-8"></script>
</body>
</html>
Файл /src/index.tsx
import * as React from 'react';
import {Component, PropTypes} from 'react';
import * as ReactDOM from 'react-dom';
// React Events
// onClick onMouseDown onMouseUp onMouseEnter onMouseLeave
// onKeyDown onKeyPress onKeyUp
// onChange onInput onSubmit onSelect
// onFocus onBlur
// onScroll
// onWheel
// image onLoad onError
interface IHeader {
identificator: string;
func(): void;
}
class Header extends Component<IHeader, {}> {
constructor (props) {
super(props);
}
render (): JSX.Element {
this.props.func();
return (
<h2
className={this.props.identificator === 'header' ? 'bold' : 'thin'}
style={{backgroundColor: 'blue', color: 'yellow'}}
data-custom-attribute="foo"
>{this.props.children}{/* Через children можно передать и функцию {this.props.children('a', 'b', 'c')} так <Header>{(a, b, c) => <p>{a} {b} {c}</p>}</Header> */}</h2>
);
}
}
class DangerouslyHTML extends Component<{}, {}> {
constructor (props) {
super(props);
}
render (): JSX.Element {
return (
<div dangerouslySetInnerHTML={{__html: '<span>·Это опасный HTML-код</span>'}}></div>
);
}
}
interface IList {
elementsArray: string[][];
}
class List extends Component<IList, {}> {
constructor(props) {
super(props);
}
render (): JSX.Element {
return (
<ul>
{
this.props.elementsArray.map((element: string[], index: number): JSX.Element => {
return <li key={index} onClick={this.handleClick.bind(this)}>{element[0]}</li>
})
}
</ul>
);
}
handleClick (event): void {
event.preventDefault();
console.log(event.target.innerHTML);
}
}
interface IFormState {
inputValue: string;
textareaValue: string;
selectValue: string;
checkboxValue: boolean;
}
class Form extends Component<{}, IFormState> {
constructor (props) {
super(props);
this.state = {
inputValue: 'Анна',
textareaValue: 'Пришла на работу',
selectValue: 'one',
checkboxValue: true
};
}
render (): JSX.Element {
return (
<form method="get" action ="/" onSubmit={this.handleSubmit.bind(this)}>
<label htmlFor="input">Имя</label>
<input ref="inputRef" type="text" disabled={false} defaultValue="Борис" value={this.state.inputValue} onChange={this.handleInputChange.bind(this)} />
<textarea ref="textareaRef" disabled={false} defaultValue="Идет домой" value={this.state.textareaValue} onChange={this.handleTextareaChange.bind(this)} />
<select ref="selectRef" disabled={false} multiple={true} value={[this.state.selectValue, 'two']} onChange={this.handleSelectChange.bind(this)}>
<option value="one">один</option>
<option value="two">два</option>
<option value="three">три</option>
</select>
<input ref="checkboxRef" type="checkbox" disabled={false} checked={this.state.checkboxValue} onChange={this.handleCheckboxChange.bind(this)} />
<input type="submit" value="Отправить" / >
<input type="reset" value="Очистить" onClick={this.handleReset.bind(this)} />
</form>
);
}
handleSubmit (event) {
event.preventDefault();
event.stopPropagation();
console.log({
input: (this.refs.inputRef as HTMLInputElement).value,
textarea: (this.refs.textareaRef as HTMLInputElement).value,
select: (this.refs.selectRef as HTMLInputElement).value,
checkbox: (this.refs.checkboxRef as HTMLInputElement).checked
});
}
handleInputChange (event) {
this.setState(
Object.assign({}, this.state, {inputValue: event.target.value.length > 5 ? event.target.value.slice(0, 5) : event.target.value}),
function () {console.log('Input changed');}
);
}
handleTextareaChange (event) {
this.setState(Object.assign({}, this.state, {textareaValue: event.targer.value}));
}
handleSelectChange (event) {
console.log(event.target.value);
}
handleCheckboxChange (event) {
this.setState(Object.assign({}, this.state, {checkboxValue: event.target.checked === true ? true : false}));
}
handleReset (event) {
event.preventDefault();
this.setState({
inputValue: '',
textareaValue: '',
selectValue: '',
checkboxValue: true
});
}
}
class Menu extends Component<{}, {}> {
constructor (props) {
super(props);
}
render (): JSX.Element {
const elements: string[][] = [
['главная', '/'],
['отчеты', '/reports'],
['контакты', '/contacts']
];
return (
<List elementsArray={elements} />
);
}
}
interface IPropsValidation {
optionalBoolean: boolean;
optionalNumber: number;
optionalString: string;
optionalOneOf: string;
optionalArray: string[];
optionalArrayOf: number[];
optionalObject: {};
optionalObjectOf: {};
optionalObjectWithShape: {
color: string;
fontSize: number;
};
optionalFunction: () => number;
requiredFunction: () => number,
// optionalSymbol: symbol;
optionalReactElement: JSX.Element;
anythingOptionalThatCanBeRendered: number | string | JSX.Element;
optionalInstanceOfClass: number[];
optionalOneOfType: number | string;
requiredAny: any;
customProp: string;
}
class PropsValidation extends Component <IPropsValidation, {}> {
static contextTypes = {
color: PropTypes.string
};
static childContextTypes = {
color: PropTypes.string
};
static defaultProps = {
optionalBoolean: true,
optionalNumber: 1,
optionalString: 'text'
};
static propTypes = {
optionalBoolean: PropTypes.bool,
optionalNumber: PropTypes.number,
optionalString: PropTypes.string,
optionalOneOf: PropTypes.oneOf(['News', 'Photos']),
optionalArray: PropTypes.array,
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
optionalObject: PropTypes.object,
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
optionalFunction: PropTypes.func,
requiredFunction: PropTypes.func.isRequired,
// optionalSymbol: PropTypes.symbol,
optionalReactElement: PropTypes.element,
anythingOptionalThatCanBeRendered: PropTypes.node, // number, string, element
optionalInstanceOfClass: PropTypes.instanceOf(Array),
optionalOneOfType: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
requiredAny: PropTypes.any.isRequired,
customProp: function (props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Invalid prop "' + propName + '" supplied to "' + componentName + '". Validation failed.');
}
}
};
constructor (props) {
super(props);
}
render (): JSX.Element {
console.log(this.props.optionalFunction());
console.log(this.props.requiredFunction());
return (
<div>
{this.props.optionalBoolean}
{this.props.optionalNumber}
{this.props.optionalString}
{this.props.optionalOneOf}
{this.props.optionalArray[0]}
{this.props.optionalArrayOf[0]}
{(this.props.optionalObject as any).one}
{(this.props.optionalObjectOf as any).three}
{this.props.optionalObjectWithShape.color}
{/* this.props.optionalSymbol */}
{this.props.optionalReactElement}
{this.props.anythingOptionalThatCanBeRendered}
{this.props.optionalInstanceOfClass}
{this.props.optionalOneOfType}
{this.props.requiredAny}
{this.props.customProp}
</div>
);
}
}
interface ILifecycleState {
comments: string[];
}
class Lifecycle extends Component<{}, ILifecycleState> {
// 1. Установка первоначальных значений.
// Выполняется только 1 раз перед вставкой компонента на страниц.
/* componentWillMount (props, context) { */ constructor (props, context) {
super(props);
/* getInitialState () {return {comments: []};} */ this.state = {comments: []};
console.log('1. Установка первоначальных значений.');
}
// 2. Рендеринг компонента.
// Выполняется при вставке компонента на страницу.
// А также каждый раз при изменении свойств this.props или состояния компонента чере this.setState()
render (): JSX.Element {
console.log('2. Рендеринг компонента.');
if (this.state.comments.length > 1) {
return (
<ul className="comments">
{
this.state.comments.map((comments) => {
return (
<li>comment</li>
);
})
}
</ul>
);
} else {
return (
<div onClick={this.forceUpdateHandler.bind(this)}>Нет данных [Обновить]</div>
);
}
}
forceUpdateHandler () {
this.forceUpdate(); // Принудительная перерисовка компонента
}
// 3. Выполнение действий после вставки компонента на страницу.
// Выполняется только 1 раз после вставки компонента на страницу.
// Здесь можно изменять размеры элементов после вставки компонента или получать данные через AJAX.
componentDidMount () {
// getData().then((data) => {
// this.setState(Object.assign({}, this.state, {comments: data}));
// });
// resizeComponent();
// this.refs.textInput.focus();
// this.timerId = setInterval(() => {this.tick();}, 1000);
console.log('3. Выполнение действий после вставки компонента на страницу.');
}
// 4. Получение новых свойств props.
// Выполняется каждый раз, когда уже вставленный на страницу компонент перезагружается и получает новые свойства props.
// Обычно не нужно менять.
componentWillReceiveProps (nextProps, nextContext) {
this.setState(Object.assign({}, this.state, {comments: nextProps.comments}));
console.log('4. Получение новых свойств при перерисовке компонента.');
}
// 5. Проверка необходимости делать ререндеринг компонента
// Выполняется каждый раз, когда уже вставленный на страницу компонент перезагружается.
// Здесь можно сделать проверку нужно ли делать ререндеринг компонента в зависимости от переданных ему свойств props.
// Данный метод обязательно должен вернуть true или false.
// Обычно не нужно менять.
shouldComponentUpdate (nextProps, nextState, nextContext) {
console.log('5. Проверка необходимости делать ререндеринг компонента');
// return this.props.id !== nextProps.id;
// return this.state.comments !== nextState.comments;
if (this.state.comments.length > 0) {
return true;
} else {
return false;
}
}
// 6. Выполнение действий перед перерисовкой компонента.
// Выполняется каждый раз перед перерисовкой компонента.
// Здесь можно устанавливать слушателей событий.
// Обычно не нужно менять.
componentWillUpdate (nextProps, nextStatem, nextContext) {
console.log('6. Выполнение действий перед перерисовкой компонента.');
}
// 7. Выполнение действий после перерисовкой компонента.
// Выполняется каждый раз после перерисовки компонента.
// Здесь можно изменять размеры элементов после вставки компонента.
// Обычно не нужно менять.
componentDidUpdate (prevProps, prevState, prevContext) {
// resizeComponent();
console.log('7. Выполнение действий после перерисовкой компонента.');
}
// 8. Выполнение действий перед удалением компонента со страницы.
// Выполняется только 1 раз перед удалением компонента со страницы.
// Здесь можно удалять слушателей событий.
componentWillUnmount () {
// document.body.removeEventListener(resize);
// clearInterval(this.timerId);
console.log('8. Выполнение действий перед удалением компонента со страницы.');
}
}
class App extends Component<{}, {}> {
constructor (props) {
super(props);
}
render (): JSX.Element {
return (
<div>
{/* Это комментарий к компоненту */}
{
// Это комментарий в конце строки
}
{true ? (
<div>Ура!</div>
) : (
<div>Ха-ха!</div>
)}
{[1, 2, 3].length > 0 && <div>Ура!</div>}
<h1>Hello</h1>
<p>
<span>Так</span>{' '}
<span>вставляется</span>{' '}
<span>множество</span>{' '}
<span>пробелов</span>
</p>
{[
<p key="1">4</p>,
<p key="2">5</p>,
<p key="3">6</p>
]}
<ul>
{[1, 2, 3].map((number, index) => {
return (<li key={index}>{number}</li>);
})}
</ul>
<Header identificator="header" func={function () {console.log('OK Header');}}>Заголовок</Header>
<DangerouslyHTML />
<Menu />
<Form />
<PropsValidation
optionalBoolean={true}
optionalNumber={1}
optionalString="text"
optionalOneOf="News"
optionalArray={['one', 'two', 'three']}
optionalArrayOf={[1, 2, 3]}
optionalObject={{one: 1, two: 2}}
optionalObjectOf={{three: 3, four: 4}}
optionalObjectWithShape={{
color: 'red',
fontSize: 10
}}
optionalFunction={function () {return 1;}}
requiredFunction={function () {return 2;}}
optionalReactElement={<Header identificator="header2" func={function () {console.log('OK Header 2');}}>Заголовок 2</Header>}
anythingOptionalThatCanBeRendered={123}
optionalInstanceOfClass={new Array(4, 5, 6)}
optionalOneOfType={15}
requiredAny="string"
customProp="matchme"
/>
<Lifecycle />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Файл /src/index-redux.tsx
import * as React from 'react';
import {Component} from 'react';
import * as ReactDOM from 'react-dom';
import {createStore, combineReducers, applyMiddleware, bindActionCreators} from 'redux';
import * as logger from 'redux-logger';
import thunk from 'redux-thunk';
import {Provider, connect} from 'react-redux';
const couterUpAction = (value) => {
return {
type: 'COUNTER_UP',
value: value
};
};
const couterDownAction = (value) => {
return {
type: 'COUNTER_DOWN',
value: value
};
};
const couterDownAsync = (value) => {
return function (dispatch) {
setTimeout(() => {
dispatch(couterDownAction(value));
}, 1000);
};
};
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'COUNTER_UP': return state + action.value;
case 'COUNTER_DOWN': return state - action.value;
default: return state;
}
};
const outterReducer = combineReducers({
inner: counterReducer
});
const rootReducer = combineReducers({
counter: outterReducer
});
const initialState = {
counter: {
inner: 0
}
};
const store = createStore(rootReducer, initialState, applyMiddleware((logger as any).createLogger(), thunk));
store.subscribe(() => {console.log(store.getState());});
interface IStateProps {
counter: number;
}
interface IDispatchProps {
handleUpClick: () => void;
handleDownClick: () => void;
}
class Counter extends Component<IStateProps & IDispatchProps, {}> {
constructor (props) {
super(props);
// this.state = {counter: store.getState()};
}
render (): JSX.Element {
const {
counter,
handleUpClick,
handleDownClick
} = this.props;
return (
<div>
<span>{counter}</span>{' '}
<span onClick={handleUpClick}>Вверх</span>{' '}
<span onClick={handleDownClick}>Вниз</span>
</div>
);
}
}
const mapStateToProps = (state): IStateProps => {
return {
counter: state.counter.inner
};
};
const mapDispatchToProps = (dispatch): IDispatchProps => {
return {
handleUpClick: function () {
dispatch(couterUpAction(1));
// this.setState(Object.assign({}, this.state, {counter: store.getState().counter}));
},
handleDownClick: function () {
dispatch(couterDownAsync(1));
// this.setState(Object.assign({}, this.state, {counter: store.getState().counter}));
}
};
};
const ConnectedCounter = connect<IStateProps, IDispatchProps, {}>(mapStateToProps, mapDispatchToProps)(Counter);
class App extends Component<{}, {}> {
render (): JSX.Element {
return (
<ConnectedCounter />
);
}
}
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
Комментариев нет:
Отправить комментарий