├── .babelrc
├── .gitignore
├── app
├── components
│ ├── basic.jsx
│ ├── childComponents
│ │ └── childA.jsx
│ ├── hello.jsx
│ └── public.jsx
├── main.js
├── page
│ ├── pageA.jsx
│ ├── pageB.css
│ ├── pageB.jsx
│ ├── pageC.css
│ ├── pageC.jsx
│ ├── pageD.jsx
│ ├── pageE.jsx
│ └── pageF.jsx
└── store.js
├── build
├── bundle.js
└── index.html
├── package.json
├── readme.md
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | //.babelrc
2 | {
3 | "presets": [
4 | "react",
5 | "es2015"
6 | ]
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/app/components/basic.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | //定义组件
5 | class Basic extends React.Component {
6 | constructor(props) {
7 | //继承与来自外部传进来的props
8 | super(props);
9 | // 设置 initial state
10 | this.state = {
11 | // 设置一个默认的props,可以通过传进来获取
12 | text: props.text || '哈哈哈',
13 | };
14 | // ES6 类中函数必须手动绑定
15 | this.handleSubmit = this.handleSubmit.bind(this);
16 | }
17 | componentDidMount() {
18 | console.log(this)
19 | }
20 | handleSubmit(event) {
21 | //借助于组件来触发,但是要注意要把event继续带过去
22 | this.props.handleSubmit(event)
23 | }
24 | render() {
25 | return(
26 |
27 | {/* 样式通过style={{}}的方法定义,里面的对象的属性值要用驼峰的写法 */}
28 |
{this.state.text}
29 |
{this.props.name}
30 |
31 |
32 | )
33 | }
34 | }
35 |
36 | export default connect((state) => {
37 | //把store里面的state共享到组件
38 | //组件里面通过this.props就可以直接获取该state的值
39 | return state
40 | }, (dispatch) => {
41 | //触发更改store里面的state
42 | //组件里面通过this.props就可以直接获取该方法
43 | return {
44 | handleSubmit: (event) => {
45 | console.log(event.target.value)
46 | //可以触发多个
47 | dispatch({
48 | type: 'SETNAME',
49 | //传递值到action中,并修改store
50 | name: event.target.value
51 | })
52 | }
53 | }
54 | })(Basic);
--------------------------------------------------------------------------------
/app/components/childComponents/childA.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/react-redux/9bb830e5ef83e6fc3214b3623f8ff475f64d1ddd/app/components/childComponents/childA.jsx
--------------------------------------------------------------------------------
/app/components/hello.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | //定义样式
5 | let style = {
6 | div: {
7 | border: '1px solid red',
8 | padding: '20px'
9 | },
10 | p: {
11 | color: "green"
12 | }
13 | }
14 |
15 | //定义组件
16 | class Hello extends React.Component {
17 | constructor(props) {
18 | super(props);
19 | // 设置 initial state
20 | this.state = {
21 | text: "这是一个hello组件"
22 | };
23 | // ES6 类中函数必须手动绑定
24 | }
25 | componentDidMount() {
26 | console.log(this)
27 | }
28 | render() {
29 | return(
30 |
31 |
{this.state.text}
32 |
{this.props.name}
33 |
34 |
35 | )
36 | }
37 | }
38 | export default connect((state) => {
39 | console.log(state)
40 | return state
41 | }, (dispatch) => {
42 | return {
43 | handleSubmit: (event) => {
44 | console.log(event.target.value)
45 | //可以触发多个
46 | dispatch({
47 | type: 'SETNAME',
48 | //传递值到action中,并修改store
49 | name: event.target.value
50 | })
51 | }
52 | }
53 | })(Hello);
--------------------------------------------------------------------------------
/app/components/public.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // 第一个公有组件
3 | class PublicA extends React.Component {
4 | constructor(props) {
5 | super(props)
6 | this.state = {
7 | content: "我是第一个公有组件"
8 | }
9 | this.OK = () => {
10 | console.log(this.state.content)
11 | }
12 | this.getInputValue = (event) => {
13 | this.setState({content: event.target.value})
14 | }
15 | }
16 | render() {
17 | return (
18 |
19 |
{this.state.content}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | // 第二个公有组件
28 | class PublicB extends React.Component {
29 | constructor(props) {
30 | super(props)
31 | this.state = {}
32 | this.OK = () => {
33 | console.log("我是第二个公有组件")
34 | }
35 | }
36 | render() {
37 | return (
38 |
39 | 第二个公有组件
40 |
41 |
42 | )
43 | }
44 | }
45 | // 默认导出一个,仅且一个
46 | // export default PublicA
47 | // 导出多个
48 | export {PublicA, PublicB}
49 |
--------------------------------------------------------------------------------
/app/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | //redux
5 | import {Provider} from 'react-redux';
6 | import store from "./store.js"
7 |
8 | //router
9 | import {Route, Link, Redirect, HashRouter} from 'react-router-dom';
10 |
11 | //page
12 | import PageA from "./page/pageA.jsx";
13 | import PageB from "./page/pageB.jsx";
14 | import PageC from "./page/pageC.jsx";
15 | import PageD from "./page/pageD.jsx";
16 | import PageE from "./page/pageE.jsx";
17 | import PageF from "./page/pageF.jsx";
18 |
19 | ReactDOM.render((
20 |
21 |
22 |
23 |
24 | -
25 | PageA
26 |
27 | -
28 | PageB
29 |
30 | -
31 | PageC
32 |
33 | -
34 | PageD
35 |
36 | -
37 | PageE
38 |
39 | -
40 | PageF
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | ), document.getElementById('root'))
53 |
--------------------------------------------------------------------------------
/app/page/pageA.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | //import store from "../store.js"
3 | import Basic from "../components/basic.jsx";
4 | import Hello from "../components/hello.jsx";
5 | // React component
6 | class PageA extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | // 设置 initial state
10 | this.state = {
11 | };
12 | }
13 | componentDidMount() {
14 | }
15 | render() {
16 | return (
17 |
18 |
PageA
19 | {/*传入了一个props,在basic组件里面接受*/}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default PageA;
28 |
--------------------------------------------------------------------------------
/app/page/pageB.css:
--------------------------------------------------------------------------------
1 | .pageb-p{
2 | color:red
3 | }
4 |
--------------------------------------------------------------------------------
/app/page/pageB.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './pageB.css';
3 | class PageB extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | // 设置 initial state
7 | this.state = {
8 | name: ""
9 | };
10 | this.sto = null
11 | }
12 | componentDidMount() {
13 | var self = this;
14 | this.sto = setTimeout(function() {
15 | self.setState({name: "我是谁,我在哪里?"})
16 | }, 1000)
17 | }
18 | componentWillUnmount() {
19 | // 手动清楚定时器,不然会出警告
20 | clearTimeout(this.sto)
21 | }
22 | render() {
23 | return (
24 |
25 |
PageB
26 | {/*三元操作表达式*/}
27 |
1.三元操作
28 |
{this.state.name
29 | ? this.state.name
30 | : "加载中"}
31 | {/*运算符||*/}
32 |
2.运算符||
33 |
{this.state.name || "加载中"}
34 |
35 | )
36 | }
37 | }
38 | export default PageB;
39 |
--------------------------------------------------------------------------------
/app/page/pageC.css:
--------------------------------------------------------------------------------
1 | .pagec-blue {
2 | color: blue;
3 | }
4 |
5 | .pagec-green {
6 | color: green;
7 | }
--------------------------------------------------------------------------------
/app/page/pageC.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './pageC.css'
3 | class PageB extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | // 设置 initial state
7 | this.state = {
8 | name: "Oaoafly",
9 | bool: true,
10 | //注意数组里面的html元素是没有双引号的
11 | //还有注意渲染数组里面的html结构,必须要有主键key,不然会有警告
12 | htmlArr: [< p key = "1" > a < /p>, b
],
13 | arr: [
14 | {
15 | name: "Oaoafly",
16 | skill: "PS"
17 | }, {
18 | name: "Wscats",
19 | skill: "CSS"
20 | }, {
21 | name: "Eno",
22 | skill: "JS"
23 | }
24 | ],
25 | html: "这是一段HTML
"
26 | };
27 | this.Ok = this.Ok.bind(this);
28 | this.ed = this.ed.bind(this);
29 | }
30 | componentDidMount() {
31 | //等到虚拟DOM插入文档以后,即componentDidMount生命周期后才能使用这个属性
32 | this.refs.nihao.style.color = "red";
33 | }
34 | Ok() {
35 | this.setState({
36 | bool: !this.state.bool
37 | })
38 | }
39 | ed(data) {
40 | //模拟过滤器
41 | return data + "ed"
42 | }
43 | render() {
44 | return (
45 |
46 | {/*通过ref来获取真是DOM节点*/}
47 |
PageC
48 |
1.函数表达式
51 |
{(function() {
52 | return "Wscats"
53 | })()}
54 |
{(function(self) {
55 | return self.state.name;
56 | })(this)}
57 |
{(function(self) {
66 | {/*v-if*/
67 | }
68 | if (self.state.bool) {
69 | return "假";
70 | } else {
71 | return "真";
72 | }
73 | })(this)}
74 |
75 | {/*过滤器*/}
76 | {this.ed(this.state.name)}
77 |
78 |
79 |
80 |
2.ref获取真实节点
81 |
82 |
3.布尔值 v-if
85 |
86 |
{!this.state.bool
87 | ? "真"
88 | : "假"}
89 |
4.数组
92 | {this.state.htmlArr}
93 |
5.渲染列表
96 |
97 | {/*注意只能有一个根节点*/}
98 | {(function(self) {
99 | return (
100 |
101 |
- 1
102 | - 1
103 |
104 | );
105 | })(this)}
106 |
107 |
108 | {this.state.arr.map(function(item, i) {
109 | {/*可以在里面出现if的条件*/
110 | }
111 | if (item.skill == 'PS') {
112 | return
113 | } else {
114 | return - {item.name}
115 | }
116 | })}
117 |
118 |
6.标签渲染
121 |
122 | {/*注意输出的
标签是没有双引号*/}
123 |
{< p > {
124 | this.state.name
125 | } < /p>}
126 |
利用dangerouslySetInnerHTML方法
129 |
130 |
{this.state.bool
131 | ?
真
132 | : 假
}
133 | {/*React默认会进行HTML的转义,避免XSS攻击,如果要不转义,可以这么写,可以把富文本this.state.html渲染到页面上*/}
134 |
137 |
138 | )
139 | }
140 | }
141 | export default PageB;
142 |
--------------------------------------------------------------------------------
/app/page/pageD.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {PublicA, PublicB} from "../components/public.jsx";
3 | class PageB extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | // 设置 initial state
7 | this.state = {};
8 |
9 | }
10 | componentDidMount() {}
11 |
12 | render() {
13 | return (
14 |
15 |
单JSX文件导出多个组件
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 | export default PageB;
23 |
--------------------------------------------------------------------------------
/app/page/pageE.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | class PageE extends React.Component {
3 | // 构造函数,在创建组件的时候调用一次
4 | constructor(props) {
5 | super(props);
6 | console.log("--------------initialrender----------------");
7 | console.log("--------------constructor----------------");
8 | this.state = {
9 | name: "生命周期"
10 | }
11 |
12 | this.getInputValue = (event) => {
13 | this.setState({name: event.target.value})
14 | }
15 | }
16 |
17 | // 创建组件的时候调用一次,这里不能用ref,因为还没挂载
18 | // 如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次
19 | componentWillMount() {
20 | console.log("--------------componentWillMount----------------")
21 | console.log(this.refs)
22 | console.log(this.state)
23 | }
24 | //在组件挂载之后调用一次。这个时候,子主键也都挂载好了,可以在这里使用refs
25 | componentDidMount() {
26 | console.log(this)
27 | console.log("--------------componentDidMount----------------")
28 | console.log(this.refs)
29 | console.log(this.state)
30 | }
31 | // props是父组件传递给子组件的。父组件发生render的时候子组件就会调用componentWillReceiveProps(不管props有没有更新,也不管父子组件之间有没有数据交换)
32 | componentWillReceiveProps() {
33 | console.log("--------------componentWillReceiveProps----------------")
34 | console.log(this.refs)
35 | console.log(this.state)
36 | }
37 | // 组件挂载之后,每次调用setState后都会调用shouldComponentUpdate判断是否需要重新渲染组件。默认返回true,需要重新render。在比较复杂的应用里,有一些数据的改变并不影响界面展示,可以在这里做判断,优化渲染效率
38 | // shouldComponentUpdate返回true或者调用forceUpdate之后,componentWillUpdate会被调用。
39 | shouldComponentUpdate() {
40 | console.log("--------------shouldComponentUpdate----------------")
41 | // 这个布尔值将决定是否触发componentWillUpdate的生命周期
42 | var reg = /[^\u4e00-\u9fa5]/;
43 | if (reg.test(this.state.name)) {
44 | return false
45 | } else {
46 | return true
47 | }
48 | }
49 | // 除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。
50 | componentWillUpdate() {
51 | console.log("--------------componentWillUpdate----------------")
52 | console.log(this.refs)
53 | console.log(this.state)
54 | }
55 | componentDidUpdate() {
56 | console.log("--------------componentDidUpdate----------------")
57 | console.log(this.refs)
58 | console.log(this.state)
59 | }
60 | // 组件被卸载的时候调用。一般在componentDidMount里面注册的事件需要在这里删除。
61 | componentWillUnmount() {
62 | console.log("--------------componentWillUnmount----------------")
63 | }
64 | // render是一个React组件所必不可少的核心函数(上面的其它函数都不是必须的)。记住,不要在render里面修改state。
65 | render() {
66 | return (
67 |
68 |
69 |
{this.state.name}
70 |
71 | )
72 | }
73 | }
74 | // 默认设置默认的props
75 | PageE.defaultProps = {
76 | name: 'ABCDEFG'
77 | }
78 | export default PageE
79 |
--------------------------------------------------------------------------------
/app/page/pageF.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {Route, Link} from 'react-router-dom'
3 | const Abc = ({match}) => (
4 |
5 |
{match.params.topicId}
6 |
7 | )
8 | const Cdf = ({match}) => (
9 |
10 |
{match.params.topicId}
11 |
12 | )
13 | class PageE extends React.Component {
14 | // 构造函数,在创建组件的时候调用一次
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | name: "路由嵌套"
19 | }
20 | }
21 | componentDidMount() {
22 | console.log(this)
23 | }
24 | render() {
25 | return (
26 |
27 |
{this.state.name}
28 |
29 | -
30 | 子路由A
31 |
32 | -
33 | 子路由B
34 |
35 |
36 | {/*可以通过:xx来接受路由参数,并在组件中用params获取*/}
37 |
38 |
39 |
40 | )
41 | }
42 | }
43 | // 默认设置默认的props
44 | PageE.defaultProps = {
45 | name: 'ABCDEFG'
46 | }
47 | export default PageE
48 |
--------------------------------------------------------------------------------
/app/store.js:
--------------------------------------------------------------------------------
1 | // Store
2 | import {createStore} from 'redux';
3 | const store = createStore(function(state = {
4 | //默认的state状态
5 | count: 0
6 | }, action) {
7 | switch (action.type) {
8 | case 'SETNAME':
9 | //return Object.assign({name: action.name}, state);方法或者...方法
10 | //返回一个新的对象到connect的第一个参数中
11 | return {name: action.name};
12 | default:
13 | return state
14 | }
15 | });
16 |
17 | export default store;
18 |
--------------------------------------------------------------------------------
/build/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React Test
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "babel-core": "6.24.1",
4 | "babel-loader": "7.0.0",
5 | "babel-preset-es2015": "6.24.1",
6 | "babel-preset-react": "6.24.1",
7 | "babel-preset-stage-0": "^6.24.1",
8 | "css-loader": "^0.28.7",
9 | "history": "4.6.1",
10 | "less-loader": "4.0.3",
11 | "react": "15.5.4",
12 | "react-bootstrap": "0.31.0",
13 | "react-dom": "15.5.4",
14 | "react-redux": "5.0.5",
15 | "react-router-config": "1.0.0-beta.3",
16 | "react-router-dom": "4.1.1",
17 | "redux": "3.6.0",
18 | "style-loader": "0.16.1",
19 | "url-loader": "0.5.8",
20 | "webpack": "2.4.1",
21 | "webpack-dev-server": "2.4.2"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # install
2 | ```bash
3 | npm install
4 | ```
5 |
6 | # run
7 | ```bash
8 | webpack-dev-server
9 | ```
10 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | //__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录
2 | module.exports = { //注意这里是exports不是export
3 | devtool: 'eval-source-map', //生成Source Maps,这里选择eval-source-map
4 | entry: __dirname + "/app/main.js", //唯一入口文件
5 | output: { //输出目录
6 | path: __dirname + "/build", //打包后的js文件存放的地方
7 | filename: 'bundle.js', //打包后的js文件名
8 | },
9 | watch: true,
10 | module: {
11 | loaders: [
12 | {
13 | test: /\.js[x]?$/, //匹配到js或jsx文件后 使用 babel-loader 来处理
14 | exclude: /node_modules/, //屏蔽不需要处理的文件(文件夹)(可选)
15 | loader: 'babel-loader'
16 | //npm install babel-loader
17 | //npm install babel-core
18 | }, {
19 | test: /\.css$/,
20 | loader: 'style-loader!css-loader'
21 | }, {
22 | test: /\.less$/,
23 | loader: 'style-loader!css-loader!less-loader'
24 | }, {
25 | test: /\.(png|jpg)$/,
26 | loader: 'url-loader?limit=25000'
27 | }
28 | ]
29 | },
30 | devServer: {
31 | contentBase: './build', //默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到"build"目录)
32 | historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
33 | inline: true, //设置为true,当源文件改变时会自动刷新页面
34 | port: 5555, //设置默认监听端口,如果省略,默认为"8080"
35 | }
36 | };
37 |
--------------------------------------------------------------------------------