├── .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 | 107 | 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 | 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 | --------------------------------------------------------------------------------