| 创建组件
| render
| props、propType、state、setState()、replaceState()
| 获取DOM this.refs.xxx 或 ReactDOM.findDOMNode(this.refs.xxx)
| React.Children 获取父组件传的DOM
| mixin
React
React包括几个概念: 1、组件 2、JSX 3、虚拟DOM 4、单向数据绑定 5、受控组件
1、核心是封装组件,只关注UI,状态变更重新渲染整个组件
2、JSX: HTML代码可以直接嵌到JS代码中,这就是React提出的叫JSX的语法,原来前端以表现和逻辑层分离为主,但HTML是组件的一部分所以不能分割,JSX 将动态值放到 { ... }
3、单向数据流: 当数据更新会渲染整个app
React的渲染方式: 用户输入 ~> 从API获取数据 ~> 将数据传给顶层组件 ~> React将每个组件渲染出来, 不会象MVC一样的双向数据绑定、和数据模型的脏值检测、不会有确切的DOM操作
4、虚拟DOM树: React重建一个DOM树,找到与上一个版本的DOM的差异,计算出新的DOM更新操作,从操作队列中指执行DOM更新操作
http://www.alloyteam.com/2015/04/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF%E8%A7%A3%E5%AF%86-virtualdom/ // 前沿技术解密——VirtualDOM
5、IE浏览器要在8.0版本以上
rrc 创建带redux组件
rcc 创建react组件
rca 创建action
reducer 创建reduer
react引用方式
// Component作为所有组件的基类,提供很多组件共有的功能
import React, { Component } from 'react';
import { reactDom } from 'react-dom';
// 定义组件
class SimpleComponent extends Component {
render(){
return <div> React,我们来了... </div>;
}
}
export default SimpleComponent;
// 组件渲染
reactDom.render(<HelloMessage />, document.getElementById('app'));
生命周期
组件的生命周期三个过程
装载过程(Mount) - 把组件第一次在DOM树中渲染的过程
更新过程(Update) - 当组件被重新渲染的过程
卸载过程(Unmount) - 组件从DOM中删除的过程
一、装载过程
1、constructor - ES6每个类的构造函数,创建一个组件就会先调用对应的构造函数
2、getInitialState() - 初始化this.state,(ES6不起作用)
3、getDefaultProps - 设置默认的props (ES6不起作用)
4、componentWillMount() - 组件挂载前(调用render方法之前触发, 没有任何渲染,就算调用了this.setState()也不会引发绘制)
5、render() - 创建虚拟dom,进行diff算法,更新dom树,如果不需要渲染可以将render函数返回一个null或false
6、componentDidMount() - 组件渲染后已经装载到DOM树中,这时候可以refs操作获取或操作DOM节点
二、更新过程(当props或state被修改时就会引发组件的更新过程)
1、componentWillReceiveProps(nextProps) - 当父组件改变了传递给子组件props的值,这时候子组件此方法会被调用
2、shouldComponentUpdate(nextProps, nextState) - react性能环节,父组件传给子组件的props值改变,子组件中的shouldComponentUpdata()方法会先调用,前后两个props相同返回false阻止更新,不需要在创建新的dom树在进行diff算法,默认为true
shouldComponentUpdate(nextProps, nextState){
return nextProps.name === nextState.name // 如果返回false就算父组件传递的props值改变,也不会执行render
}
3、componentWillUpdate() - 与装载过程相同
4、render() - 与装载过程相同
5、componentDidUpdate() - 与装载过程相同
三、卸载组件
1、componentWillUnmount() - 卸载前调用
JSX语法
一、注释
{/* 这里用于单多行注释 */}
二、根元素只能有一个
class ComponentDemo extends Component {
render(){
// 以下写法直接报错
return (
<div>
hello
</div>
);
}
}
三、属性名不能和 js 关键字冲突
1、class => className
2、read => readOnly
3、for => htmlFrom 不能直接使用for
<div htmlFor='male'>Male</div>
四、JSX spread
{ ...spreadObj } 可以直接将spreadObj的对象传递过去
import SpreadDemo from './components/spread';
const spreadObj = {
name: 'siguang',
carType: '卡宴'
}
render(<SpreadDemo {...spreadObj} />, document.querySelector('#app'));
五、渲染HTML
const elements = '<p>aaa</p><p>bbb</p><p>ccc</p>';
<p dangerouslySetInnerHTML={{ __html: elements }}></p>
http://lib.csdn.net/article/react/22655
class和style
一、class
方法1:
import './admin.css'
render() {
return (
<div className="container"> // 注意这里的值为字符串而不是{}
<div className="sild">xxxx</div>
</div>
);
}
方法2:
import styles from './admin.css'
render() {
return (
<div>
<div className={style.sild}>xxxx</div>
</div>
);
}
二、style 行内样式
方法1:
const container = {
display: flex;
height: 100%;
}
render() {
return (
<div style={container}> xxx </div>
);
}
方法2: <div style={{ width: '100px', float: 'left'}}> // 注意这里属性值要使用引号
组件
一、组件创建
1、类式组件
import React, { Component } from 'react'
import ReactDom, { render } from 'react-dom'
// 所有创建的组件都继承于Component对象
class ShowMessage extends Component{
constructor(props){
super(props);
}
render(){
return <div>Hello name {this.props.name}</div>
}
}
export default ShowMessage;
2、函数式组件
const Welcome = (props) => {
return <h1>Hello, {props.name}</h1>;
}
<Welcome username="this.state.username" />
函数组件与类式组件的区别:
类组件有state, 函数组件没有state
类组件有生命周期函数
二、组件注意的地方
1、组件名首字母必须大写
2、根元素只能有一个标签元素
class ComponentDemo extends Component {
render(){
return (
<div class="boxA"> {/* 根元素只能有一个 */}
aaaaaaaa
<div class="boxB">
bbbbbb
</div>
</div>
)
}
}
export default ComponentDemo;
3、可以使用es6的 spread 变量传递 {...obj}
let person = <Person name={window.isLoggedIn ? window.name : ''} />
4、refs属性获取真实的DOM节点
组件并不是真实的DOM节点,而是在内存中的一种数据结构叫虚拟DOM,如果要从组件内获取真实的DOM节点,需要用到refs属性
组件嵌套
childList.jsx:
class ChildrenA extends Component{
constructor(props){
super(props);
}
render(){
return (<div>
{/* 这里是子组件A this.props.children获取组件的内容,相当前于vue中的solt */}
{
React.Children.map(this.props.children, function(c){ // React.Children是获取组件中的元素
return <p>{c}</p>
})
}
</div>)
}
}
class ParentComponent extends Component{
render(){
return <div>
<ChildrenA>
<p>福特</p>
<p>丰田</p>
<p>本田</p>
</ChildrenA>
</div>
}
}
export default ParentComponent;
index.js:
import ParentComponent from './components/ParentComponent'
render(<ParentComponent />, docuemnt.querySelector('#box'));
组件间通信
一、组件之间通信的几种情况
1、父组件向子组件通信
2、子组件向父组件通信
3、跨级组件之间通信
4、非嵌套组件间通信
二、父向子通信 通过props
parent.jsx
<child message={this.state.sayMessage} />
child.jsx
{this.props.message} // 接收
三、子向父通信
parent.jsx
<child getMessage={this.getMessage.bind(this)} />
getMessage(msg){
this.setDate({message: msg})
}
child.jsx
this.props.getMessage('这里告诉父组件消息')
四、跨级组件
父组件向很深的几层子组件通信有两种方法: 1、props一层一层传 2、使用context对象
五、events非嵌套组件通信, 使用事件订阅
$ npm i events --save
1、创建一个ev.js
import { EventEmitter } from 'events'
export default new EventEmitter();
2、brotherA.jsx
// 在组件装载完成以后
componentDidMount(){
// 声明一个自定义事件
this.eventEmitter = emitter.addListener("callMe", (msg)=>{
this.setState({
msg
})
});
}
// 组件销毁前移除事件监听
componentWillUnmount(){
emitter.removeListener(this.eventEmitter);
}
render(){
return (
<div>
{this.state.message}
</div>
)
}
3、brotherB.jsx
sendBrotherMessage(){
return emitter.emit("callMe", "Hello"); // callMe为自定义函数,hello为发的消息参数
}
<input type="button" value="向A子组件发消息" onClick={this.sendBrotherMessage.bind(this)} />
六、redux或其它状态管理库
Context对象
context对象来跨级传递
context与react版本分两种写法,以下为react v16.3版本的示例
一、React.crateContext() - 创建一个Context
二、初始化createContext下的方法
1、provider - 父组件中传递的值
2、consumeer - 子组件接收的值
三、示例:
创建一个contextStor.js:
import React, { Component } from 'react'
export const { Provider, Consumer } = React.createContext("Light"); // 默认主题是Light
parentPage.jsx:
import Ca from './cA'
import { Provider } from './ccontextStor';
export default class ParnentPage extends Component {
render () {
return (
<Provider value={{contextVal: '这里是context的传递的内容'}}>
<h1>这里是Parent组件</h1>
<Ca />
</Provider>
)
}
}
cA.jsx:
import Cb from './cB'
export default class Ca extends Component {
render () {
return (
<div>
<h2>这里是CA</h2>
<Cb />
</div>
)
}
}
cB.jsx:
import { Consumer } from './ccontextStor';
export default class Cb extends Component {
render () {
return (
<div>
<h3>这里子CB</h3>
<Consumer>
{
context => {
return (
<div>{context.contextVal}</div>
)
}
}
</Consumer>
</div>
)
}
}
数据流
React是单向数据流,数据从父组件传到子组件,子组件通过props获取数据,顶层组件改变了props,React会遍历整个组件树,重新渲染整个组件
数据流包括: Props 和 State
props
{ this.props.name } 读取props的值
一、props API:
this.props.children - 所有子组件的内容
<ChildrenComponent>
<p>aa</p>
<p>bb</p>
<p>cc</p>
</ChildrenComponent>
this.props.map
this.props.filter
二、设置一个默认的props
/* 通过 defaultProps 来定义 */
class PropsDemo extends Component {
constructor(props) {
super(props); // 调用父类,如果不写会调不到
}
render(){
return (
<div class="box">
name: {this.props.name}, age: {this.props.age}
</div>
)
}
}
// 初始化props
PropsDemo.defaultProps = {
name: '123123' // 默认一个name值,如果父组件没有传值就会取默认值
}
三、propsType 校验props类型
$ npm install --save prop-types
import React, { Component, PropTypes } from 'react';
class PropTypesDemo extends Component {
render(){
return <b>{this.props.title}</b>
}
}
// 静态属性定义propTypes, title只能为string
PropTypesDemo.propTypes = {
title: React.PropTypes.string.isRequired
}
export default PropTypesDemo;
四、Example
PropsComponent组件:
class PropsComponent extends Component {
render(){
return (
<div class="box">
name: {this.props.name}, age: {this.props.age} {/* 这里接收props值 */}
</div>
)
}
}
// 输出组件接口
export default PropsComponent;
index.js:
import PropsComponent from '../components/props';
// 要传的值
let obj = {
name: 'haha',
age: '300'
}
// 方法1、直接传给属性
render(<PropsComponent name={obj.name} age={obj.age} />, document.querySelector('body'));
// ...obj 来对多值进行解析赋值
render(<PropsComponent {...obj} />, document.querySelector('body'));
五、this.props.children 访问自定义子节点
// 将组件下的所有子节点通过map获取到,并重新包装
import React, { Component } from 'react';
class UseChildren extends Component {
render(){
return <ul>
{
// 会将UseChildren组件下所有的元素取出
React.Children.map(this.props.children, function(c){
return <li> {c} </li>
})
}
</ul>
}
}
class ChildrenDemo extends Component {
render(){
return (
<UseChildren>
<a href="#">Facebook</a>
<a href="#">Google</a>
<a href="#">Space</a>
</UseChildren>
)
}
}
export default ChildrenDemo;
六、this.props.content 可以传任意结构的JSX结构
// 父组件通过content传值
<ContentChildrenComponent content={
<div>
<h2>React.js 小书</h2>
<div>开源、免费、专业、简单</div>
订阅:<input />
</div>
} />
// 子组件调用
render() {
return (
<div>
{ this.props.content }
</div>
);
}
七、组件传值
<ChildComponent propsData={this.state.username} />
<LikeButton wordings={{likedText: '已赞', unlikedText: '赞'}} onClick={() => console.log('Click on like button!')}/>
state
每一个React组件都有一个自己的state对象,与props区别是state只能在当前组件内部使用,props可以将数据传递给子组件
一、初始化state
class StateDemo extends Component {
constructor(){
super(); // 继承Component
// 这里初始化state
this.state = {
userName: 'siguang'
}
}
setUserName: function(){
this.setState({userName: 'lulu'}); // 修改state值
},
render(){
return (
<div>
这里是props获取的值 {this.state.userName}; // 获取state的值
<input type="button" onClick={this.setUserName.bind(this)} value="点击修改state" />
</div>
)
}
}
二、setState中this的指向
1、<Button type="primary" onClick={ this.addCar.bind(this) }>开始</Button>
<Button type="primary" onClick={ (e) => this.addCar(e) }>开始</Button> // 渲染中箭头函数
2、<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
3、addCar = () => {
this.setState(function(state, porps){
return {
car: state.car + 1
}
})
}
<Button type="primary" onClick={ this.addCar }>开始</Button>
三、setState()异步的问题
setState()是异步导致如果直接在下面在取state值还没变过来,所以第二个回调是当state值设置成功后在执行的函数
this.setState(
{ username: uname },
() => { console.log(this.state.username); } // 这里还是为之前的值而不是「sg」
);
refs操作真实DOM
获取ref: this.refs.xxx
Example:
class RefsDemo extends Component {
componentDidMount(){
// refs直接获取
const contentB = this.refs.content;
console.log( contentB.innerHTML );
}
render(){
return(
<div>
<h3>React操作DOM</h3>
<p ref="content">这里是DOM元素的内容</p> // 这里定义ref访问的名
</div>
)
}
}
mixin
通过mixin可以将组件间共享代码,将两个组件共同的属性、方法存储到mixin对象中
mixin不支持ES6的声明组件方式
ES5写法
import React from 'react';
// 抽取出的公用方法
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var MixinDemo = React.createClass({
// 这里加载mixin
mixins: [SetIntervalMixin],
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
// Call a method on the mixin
this.setInterval(this.tick, 1000);
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
计时器已经运行了: {this.state.seconds} 秒.
</p>
);
}
});
export default MixinDemo;
表单
一、defaultValue 与 value 的区别
<input type="text" value={this.state.inputValue} />
如果使用 value来绑定state的值,输入值时不会被改变,使用 defaultValue 值会被改变
class App extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
handleUsername(e){
const val = e.target.value;
this.setState({username: val});
}
getName(){
alert(this.state.username)
}
render() {
return (
<div className="App">
<input placeholder="Basic usage" defaultValue={this.state.username} onChange={this.handleUsername.bind(this)} />
<button type="primary" onClick={this.getName.bind(this)}>Primary</button>
</div>
);
}
}
二、react表单组件与html的不同
1、value、checked: 属性设置值后,用户输入无效
2、textarea: 的值要设置在value属性
<textarea name="description" value="This is a description." />
3、select: value属性可以是数据,不建使用option的selected属性
<select multiple={true} value={['B', 'C']}>
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
4、radio/checkbox/option 点击后触发 onChange
受控组件
受控组件就是为某个form表单组件添加value属性;非受控组件就是没有添加value属性的组件
一、受控组件
<input>,<textarea>以及<select>通常保持自己的状态和基于用户输入更新它
handleChange(event) {
this.setState({value: event.target.value});
}
<input type="text" value={this.state.value} onChange={this.handleChange} />
二、不受控制组件
this.input = React.createRef(); // 创建不受控组件
<input type="text" ref={this.input} /> // 绑定
this.input.current.value // 调用不受控组件
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
// 创建不受控组件
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
碎片
render的时候需要有一个父的元素,如果组件嵌套会多出来无用的元素,可以使用<React.Fragment> ... </React.Fragment>
class Columns extends React.Component {
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
}
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns /> // 输出<div> ... </div>
</tr>
</table>
);
}
}
可以写成
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
React脚手架搭建
一、可以使用官网的 create-react-app、ant或自己搭 https://github.com/facebook/create-react-app
二、使用的JSX和ES6所以需要转换,使用版本:
react: "^15.4.2", react-dom: "^15.4.2", react-router: "^2.0.0"", webpack: "^3.10.0", webpack-dev-server: "^2.11.1"
react 16以上版本和 react-router 4以上版本会有问题
三、搭建
$ npm init
$ npm i react react-dom react-router --save
$ npm i webpack webpack-dev-server --save
2、安装插件
$ npm i babel babel-loader babel-core babel-preset-es2015 babel-preset-react --save
$ npm i node-sass file-loader url-loader css-loader sass-loader style-loader --save
$ npm i react-hot-loader prop-types events react-slot --save // react组件,热更新、检测props类型、事件用来通信包、slot
$ npm i html-webpack-plugin open-browser-webpack-plugin --save // 自动引入静态资源到相应的html、自动打开浏览器
$ touch .babelrc webpack.config.js
$ mkdir src && cd src && touch index.html app.js
$ .babelrc 加入
{
"presets": ["es2015", "react"]
}
$ webpack.config.js
/**
* User: siguang
* Date: 2016/12/28
* Time: 15:04
*/
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const openBrowserWebpackPlugin = require('open-browser-webpack-plugin');
const basePath = __dirname;
const appPath = path.resolve(basePath, 'src');
const buildPath = path.resolve(basePath, 'build');
module.exports = {
entry: {
app: path.resolve(appPath, 'app.js')
},
output: {
path: buildPath,
filename: '[name].min.js?[hash]',
// chunkFilename: "[name].min.js?[hash]"
},
module: {
loaders: [
// 处理require()引入的css文件,并将代码显示到页面的<style>中
{ test: /\.css$/, loader: "style-loader!css-loader" },
// 将scss文件转成css文件
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
// ?limit=8192 limit设置小于8k的图片转成64位编码,大小8于不会被转码
{ test: /\.(png|jpg|woff|eot|ttf|svg|gif)$/, loader: 'url-loader?limit=8192'},
// ES6 转 ES5
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015','react']
}
}
]
},
plugins: [
// 压缩打包的文件
new webpack.optimize.UglifyJsPlugin({
compress: {
//supresses warnings, usually from module minification
warnings: false
}
}),
// html
new HtmlWebpackPlugin({
// 改变页面的<title>标签的内容
title: 'Hello World app',
// 模版地址
template: path.resolve(appPath, 'index.html'),
// 构建后的文件名和目录
filename: 'index.html',
//chunks这个参数告诉插件要引用entry里面的哪几个入口
// chunks:['app'],
//要把script插入标签里
inject:'body'
}),
// 热启动
new webpack.HotModuleReplacementPlugin(),
// 自动打开浏览器
new openBrowserWebpackPlugin({ url: 'http://localhost:3000' })
],
// 查找依赖
resolve:{
// require或alias时不需要写后缀
extensions: [".js", ".jsx", ".css", ".json"],
},
// webpack-dev-server 配置
devServer: {
port: 3000, // 端口
contentBase: 'build', // 内容目录
hot: true, // 热刷新
inline: true
}
}`
$ package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --progress --profile --colors --hot --inline --history-api-fallback",
"build": "webpack --progress --profile --colors --config webpack.production.config.js"
},
$ 运行
$ npm run dev 生产环境,并打开webpack服务器
$ webpack 执行打包到build目录线上环境使用
https://segmentfault.com/a/1190000005969488
Diff算法
当组件更新时候,react会创建一个新的虚拟dom树并会和之前的dom树进行比较,这个过程就用到了diff算法
常用插件
https://github.com/enaqx/awesome-react#boilerplates
1、路由 - react-router
2、布局 - react-blocks http://whoisandie.github.io/react-blocks/
3、拖拽 - react-dnd https://github.com/react-dnd/react-dnd
4、代码编辑器 - react-codemirror https://github.com/JedWatson/react-codemirror
5、富文本编辑器 - react-quill react-draft-wysiwyg https://github.com/jpuri/react-draft-wysiwyg
6、拾色器 - rc-color-picker、react-color https://github.com/react-component/color-picker http://casesandberg.github.io/react-color/
7、响应式 - react-responsive、react-media https://github.com/contra/react-responsive https://github.com/ReactTraining/react-media
8、复制到剪贴板 - react-copy-to-clipboard https://github.com/nkbt/react-copy-to-clipboard
9、管理 document head - react-helmet https://github.com/nfl/react-helmet
10、Font Awesome 图标 - react-fa https://github.com/andreypopp/react-fa
11、二维码 - qrcode.react https://ant.design/docs/react/recommendation-cn
12、不在使用className - styled-components
http://www.alloyteam.com/2017/05/guide-styled-components/
https://github.com/styled-components/styled-components
13、react写动画效果 - css3transform-react
$ npm install css3transform-react
http://www.alloyteam.com/2016/12/react-animations-difficult-to-write-try-react-transformjs/
react-slot - react中写solt http://npm.taobao.org/package/react-slot
积累问题
1、jsx中for循环出标签并插入到render中, 或使用map
class SideBar extends Component {
constructor(props) {
super(props);
this.state ={
menu: [
{
path: '/home',
name: '主页'
},
{
path: '/parentToChild',
name: '将父向子组件传数据'
},
]
}
}
render() {
// 定义一个返回菜单html内容的方法
let renderMenuHtml = () => {
let homeHtml = [];
this.state.menu.forEach(function(item, idx, arr){
homeHtml.push(<li>
<Link to={item.path}>{item.name}</Link>
</li>)
})
return homeHtml
}
// 另一种写法map推荐
{/*
var renderMenuHtml = this.state.menu.map(function(c){
return(
<li>
<Link to={item.path}>{item.name}</Link>
</li>
);
});
*/}
return (
<div className="side-box">
<ul>
{renderMenuHtml()} {/* 插入内容 */}
</ul>
</div>
);
}
}
2、使用redux子组件会取不到 this.props.history
因为redux会将值传给props,所以就需要通过context来获取
解决方法: 在子组件中
import PropTypes from 'prop-types'
子组件名.contextTypes = {
router: PropTypes.object.isRequired
}
console.log( this.context.router.history.push('/') );
3、子组件调用父组件中的方法
class ComponentClider extends Component {
constructor(props){
super(props);
}
render(){
return(
<div>{ this.props.add(111,555) }</div>
)
}
}
export default ComponentParent extends Component {
add(a, b){
return a + b;
}
sub(a, b) {
return a - b;
}
render(){
return (
<div>
{/* 这里可以父组件中自己的方法直接调用 */}
{ this.add(100, 200) }
{ this.sub(200, 10) }
<ComponentClider add={(a, b) => this.add(a, b)} sub={(a, b) => this.sub(a, b)}></ComponentClider>
</div>
)
}
}
<!-- 父组件也可以写成 -->
export default ComponentParent extends Component {
multiplicative(a, b) {
return a * b
}
add = (a, b) => {
return a + b;
}
sub = (a, b) => {
return a - b;
}
render(){
const propsFun = {
add: this.add,
sub: this.sub
}
return (
<div>
{/* 这里可以父组件中自己的方法直接调用 */}
{ this.multiplicative(100, 200) }
<ComponentClider {...propsFun}></ComponentClider>
</div>
)
}
}
4、react原生动态添加多个className会报错
// 下面的引用会报错
import style from './style.css'
<div className={style.class1 style.class2}</div>
// 解决 使用classnames
$ npm install classnames --save
import classnames from 'classnames'
import styles from './index.less';
const clsString = classNames(styles.submit, className);
<div className={clsString}></div>
常用插件
1、react-document-title 根据不同的路由改变文档的title
https://www.jianshu.com/p/07ed93350483
2、react-container-query 媒体查询 响应式组件
3、classnames react引用多个className会报错问题
Antd UI组件问题收集
1、Table的每页条数 通过pagination属性来控制分页的内容
<Table pagination={{ pageSize: this.state.queryInfo.pageSize }} rowSelection={rowSelection} columns={columns} dataSource={data} />
https://www.cnblogs.com/jenifurs-blog/p/6020737.html
| https://react.docschina.org/docs/hello-world.html
| http://www.css88.com/react/docs/try-react.html
| https://juejin.im/post/5a9410c25188257a61325eda // react 新老context
| https://www.jianshu.com/p/fb915d9c99c4 // 组件通信
| http://huziketang.com/books/react/
| http://blog.csdn.net/liwusen/article/category/6522963
| http://react-china.org/ 中文社区
| https://github.com/BruceCham/react-cli // 全家桶
| http://www.alloyteam.com/2015/04/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF%E8%A7%A3%E5%AF%86-virtualdom/ // virturalDOM 虚拟DOM
| https://github.com/gaearon/redux-devtools // redux-devtools
| https://guoyongfeng.github.io/book/
| http://uprogrammer.cn/react-tutorial-cn/
| http://huziketang.com/books/react/lesson1
| https://github.com/hyy1115/react-redux-webpack2
| https://github.com/zhbhun/react-learning/tree/master/boilerplate
| http://blog.csdn.net/u013063153/article/details/52497271 // 事件
| https://github.com/gaearon/babel-plugin-react-transform#transforms // babel-plugin-react-transform 相关插件
| http://www.alloyteam.com/2016/03/using-react-to-write-a-simple-activity-pages-design-of-operating-system-article/
| https://juejin.im/post/5a84682ef265da4e83266cc4 // 源码解析
| https://www.jianshu.com/p/ec7c2bab16cc?utm_campaign=maleskine&utm_content=note&utm_medium=pc_all_hots&utm_source=recommendation // vscode 调试react 通过debugger for chrome
国内查看评论需要代理~