Skip to content

Commit

Permalink
项目重构
Browse files Browse the repository at this point in the history
  • Loading branch information
bailicangdu committed Jan 12, 2018
1 parent 41af10b commit 9f7d7bd
Show file tree
Hide file tree
Showing 183 changed files with 4,185 additions and 4,409 deletions.
13 changes: 3 additions & 10 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
{
"presets": [
"react",
"es2015",
"stage-0",
],
"plugins": [
"transform-decorators-legacy",
"transform-class-properties"
]
}
"presets": ["react"],
"plugins": ["syntax-dynamic-import"]
}
27 changes: 24 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
node_modules
npm-debug.log
data
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
*.idea
*.iml

npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
yarn.lock
40 changes: 24 additions & 16 deletions README.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@

## 技术栈:
```
react: v16.2
redux: v3.7
webpack: v3.8
react-router: v4.2
ES6/7/8
code split
hot loader
less: v2.7
axios: v0.17
immutable: v3.8
react + react-router + redux + immutable + less + ES6/7 + webpack + fetch

```

## 运行项目(nodejs 6.0+)

Expand All @@ -11,27 +21,25 @@ react + react-router + redux + immutable + less + ES6/7 + webpack + fetch
cd react-pxq
npm install
npm i
npm run dev (正常编译模式) 或 npm run hot (热替换编译模式) 二选其一
访问 http://localhost:8088
npm start
npm run dist (发布)
npm run build (发布)
```


## 说明

> 本项目主要理解 react 和 redux 的原理,以及 react + redux 之间的配合方式
> 本项目主要用于理解 react 和 redux 的编译方式,以及 react + redux 之间的配合方式
> 如果觉得不错的话,您可以点右上角 "Star" 支持一下 谢谢! ^_^
> 或者您可以 "follow" 一下,我会不断开源更多的有趣的项目
> 如有问题请直接在 Issues 中提,或者您发现问题并有非常好的解决方案,欢迎 PR 👍
> 开发环境 macOS 10.12.3 Chrome 56 nodejs 6.10.0
> 开发环境 macOS 10.13.1 Chrome 63 nodejs 8.9.1
>  推荐一个 vue2 + vuex 构建的 45 个页面的大型开源项目。[地址在这里](https://github.com/bailicangdu/vue2-elm)
Expand All @@ -43,7 +51,7 @@ react + react-router + redux + immutable + less + ES6/7 + webpack + fetch
[查看演示效果](http://cangdu.org/pxq/)(请用chrome的手机模式预览)

### 移动端扫描下方二维码
![](https://github.com/bailicangdu/pxq/blob/master/src/images/demo.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/demo.png)



Expand All @@ -68,7 +76,7 @@ react的diff算法用在什么地方呢?当组件更新的时候,react会创

对于列表的diff算法稍有不同,因为列表通常具有相同的结构,在对列表节点进行删除,插入,排序的时候,单个节点的整体操作远比一个个对比一个个替换要好得多,所以在创建列表的时候需要设置key值,这样react才能分清谁是谁。当然不写key值也可以,但这样通常会报出警告,通知我们加上key值以提高react的性能。

![](https://github.com/bailicangdu/pxq/blob/master/src/images/diff.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/diff.png)



Expand All @@ -77,7 +85,7 @@ react的diff算法用在什么地方呢?当组件更新的时候,react会创

组件的创造方法为React.createClass() ——创造一个类,react系统内部设计了一套类系统,利用它来创造react组件。但这并不是必须的,我们还可以用es6的class类来创造组件,这也是Facebook官方推荐的写法。

![](https://github.com/bailicangdu/pxq/blob/master/src/images/icon_class.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/icon_class.png)

这两种写法实现的功能一样但是原理却是不同,es6的class类可以看作是构造函数的一个语法糖,可以把它当成构造函数来看,extends实现了类之间的继承 —— 定义一个类Main 继承React.Component所有的属性和方法,组件的生命周期函数就是从这来的。constructor是构造器,在实例化对象时调用,super调用了父类的constructor创造了父类的实例对象this,然后用子类的构造函数进行修改。这和es5的原型继承是不同的,原型继承是先创造一个实例化对象this,然后再继承父级的原型方法。了解了这些之后我们在看组件的时候就清楚很多。

Expand All @@ -90,7 +98,7 @@ react的diff算法用在什么地方呢?当组件更新的时候,react会创

## 组件的生命周期

![](https://github.com/bailicangdu/pxq/blob/master/src/images/react-lifecycle.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/react-lifecycle.png)

**组件在初始化时会触发5个钩子函数:**

Expand Down Expand Up @@ -207,7 +215,7 @@ react推崇的是单向数据流,自上而下进行数据的传递,但是由
#### 流程是这个样子的:


![](https://github.com/bailicangdu/pxq/blob/master/src/images/simple_redux.jpg)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/simple_redux.jpg)

值得注意的是connect,Provider,mapStateToProps,mapDispatchToProps是react-redux提供的,redux本身和react没有半毛钱关系,它只是数据处理中心,没有和react产生任何耦合,是react-redux让它们联系在一起。

Expand All @@ -217,7 +225,7 @@ react推崇的是单向数据流,自上而下进行数据的传递,但是由

#### 先上一张图

![](https://github.com/bailicangdu/pxq/blob/master/src/images/all_redux.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/all_redux.png)

明显比第一张要复杂,其实两张图说的是同一件事。从上而下慢慢分析:

Expand Down Expand Up @@ -369,7 +377,7 @@ import { Router, Route, Redirect, IndexRoute, browserHistory, hashHistory } from

通常我们在顶层的ui组件打印props时可以看到一堆属性:

![](https://github.com/bailicangdu/pxq/blob/master/src/images/react_props.png)
![](https://github.com/bailicangdu/pxq/blob/master/screenshot/react_props.png)

上图的顶层ui组件属性总共有18个,如果刚刚接触react,可能对这些属性怎么来的感到困惑,其实这些属性来自五个地方:

Expand Down
58 changes: 58 additions & 0 deletions bin/react-scripts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env node
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const spawn = require('react-dev-utils/crossSpawn');
const args = process.argv.slice(2);

const scriptIndex = args.findIndex(
x => x === 'build' || x === 'eject' || x === 'start' || x === 'test'
);
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];

switch (script) {
case 'build':
case 'eject':
case 'start':
case 'test': {
const result = spawn.sync(
'node',
nodeArgs
.concat(require.resolve('../scripts/' + script))
.concat(args.slice(scriptIndex + 1)),
{ stdio: 'inherit' }
);
if (result.signal) {
if (result.signal === 'SIGKILL') {
console.log(
'The build failed because the process exited too early. ' +
'This probably means the system ran out of memory or someone called ' +
'`kill -9` on the process.'
);
} else if (result.signal === 'SIGTERM') {
console.log(
'The build failed because the process exited too early. ' +
'Someone might have called `kill` or `killall`, or the system could ' +
'be shutting down.'
);
}
process.exit(1);
}
process.exit(result.status);
break;
}
default:
console.log('Unknown script "' + script + '".');
console.log('Perhaps you need to update react-scripts?');
console.log(
'See: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#updating-to-new-releases'
);
break;
}
99 changes: 99 additions & 0 deletions config/env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// @remove-on-eject-begin
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
'use strict';

const fs = require('fs');
const path = require('path');
const paths = require('./paths');

// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];

const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}

// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);

// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv').config({
path: dotenvFile,
});
}
});

// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);

// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;

function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: publicUrl,
STATIC_ENV: process.env.STATIC_ENV || 'development',
}
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};

return { raw, stringified };
}

module.exports = getClientEnvironment;
15 changes: 15 additions & 0 deletions config/jest/babelTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @remove-file-on-eject
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const babelJest = require('babel-jest');

module.exports = babelJest.createTransformer({
presets: [require.resolve('babel-preset-react-app')],
babelrc: false,
});
22 changes: 22 additions & 0 deletions config/jest/cssTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @remove-on-eject-begin
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
'use strict';

// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/tutorial-webpack.html

module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};
20 changes: 20 additions & 0 deletions config/jest/fileTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @remove-on-eject-begin
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
'use strict';

const path = require('path');

// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/tutorial-webpack.html

module.exports = {
process(src, filename) {
return `module.exports = ${JSON.stringify(path.basename(filename))};`;
},
};
Loading

0 comments on commit 9f7d7bd

Please sign in to comment.