Fork me on GitHub

react notes

生成项目

webpack-react

1
2
3
npm install yo -g
npm install generator-react-webpack -g
yo react-webpack my-project

webpack-react 缺点:webpack 版本低,升级的话有一些插件要更改,不如不用了。
yeoman 容易下载失败,要用cnpm

自己写框架

感觉已有的就已经不错了,

  1. 安装react react react-dom
  2. 启用es6和JSX,配置.babelrc babel-preset-react babel-preset-env
    => npm install react react-dom babel-preset-react babel-preset-env
  3. webpack
    => 最简单的配置 npm install webpack webpack-dev-server –save // 全局要有
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    module.exports = {
    context:__dirname + '/src',
    entry:'./index.js',
    module:{
    loaders:[{
    test:/\.js?$/,
    exclude:/(node_modules)/,
    loader:'babel-loader',
    query:{
    presets:['react','es2015']
    }
    }]
    },
    output:{
    path:__dirname + '/src',
    filename:'bundle.js'
    }
    }

webpack

  1. css与image要在js中引用,才会打包
  2. 并且react中图片不自动打包,要用require引用图片路径:
    <img src={require('../../images/logo.png')} />才可以并且应该是直接打包到了js中
  3. 热更新问题 server中设置hot为true无效,而webpack-dev-server就可以直接热更新

react

ReactDOM.render()

  • ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
    1
    2
    3
    4
    ReactDOM.render(
    <Root/>,
    document.getElementById('root')
    )

JSX 的基本语法规则:

  • 遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;
  • 遇到代码块(以 { 开头),就用 JavaScript 规则解析。
  • 解析state或props里面的html标记( >等),要使用转义字符或者dangerouslySetInnerHTML
  • 不太支持 if-else,支持三元符/函数
1
<h1 dangerouslySetInnerHTML={{__html:this.state.html}}></h1>

组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Header extends React.Component{
constructor(props){
super(props);
this.state = {
...
}
}
static get defaultProps(){
return {
...
}
}
render(){
return (
<div>
...
</div>
)
}
}
export default Header

注意点:

  • 用class定义组件,初始化state要用constructor(es6),(es5)用getinitialState;初始化props要用static get defaultProps;
  • 或者在class外定义 react.defaultProps,propTypes。
  • 组件类的第一个字母必须大写,否则会报错,比如Header不能写成header。
  • 组件类只能包含一个顶层标签,否则也会报错。
  • class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
  • 传递props
    name 属性就可以通过 this.props.name 读取
  • 组件也可以用参数的形式传递
  • 组件内的state是自身属性。props是外来属性。

this.props.children

  • 它表示组件的所有子节点
  • this.props.children 的值有三种可能:
    • 没有子节点,它就是 undefined ;
    • 一个子节点,数据类型是 object;
    • 多个子节点,数据类型就是 array 。
  • React.Children.map 来遍历子节点,而不用担心this.props.children的数据类型。
    * 将父组件状态传递个下面的所有子组件:{ React.cloneElement(this.props.children , this.state) }

PropTypes

* 组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求

  • propTypes: { title: React.PropTypes.string.isRequired }

获取真实的DOM节点

1
2
3
4
<div ref="progressBar"></div>
let progressBar = this.refs.progressBar
或者ReactDOM.findDOMNode('id')
  • Refs是访问组件内部DOM节点唯一可靠的方法
  • Refs会自动销毁对子组件的引用
  • 不要在render或render之前对Refs进行调用 =》DidMount中调用
  • 不要滥用Refs

state与props

  • this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。
  • 表单的填入就要用state,不能用props.

setState

setState不会立即改变React组件中state的值。

function incrementMultiple() {
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
}

==>>

function incrementMultiple() {
  const currentCount = this.state.count;
  this.setState({count: currentCount + 1});
  this.setState({count: currentCount + 1});
  this.setState({count: currentCount + 1});
}

在React中,一个组件中要读取当前状态用是访问this.state,但是更新状态却是用this.setState,不是直接在this.state上修改,为什么呢?

因为this.state说到底只是一个对象,单纯去修改一个对象的值是没有意义的,去驱动UI的更新才是有意义的

setState通过引发一次组件的更新过程来引发重新绘制

setState调用引起的React的更新生命周期函数4个函数(比修改prop引发的生命周期少一个componentWillReceiveProps函数),这4个函数依次被调用。

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

当shouldComponentUpdate函数被调用的时候,this.state没有得到更新。
当componentWillUpdate函数被调用的时候,this.state依然没有得到更新。

直到render函数被调用的时候,this.state才得到更新。

多次setState函数调用产生的效果会合并

react生命周期

  • 组件的生命周期分成三个状态:
    • 装载过程 Mounting:已插入真实 DOM
    • 更新过程 Updating:正在被重新渲染
    • 卸载过程 Unmounting:已移出真实 DOM
  • React 为每个状态都提供了两种处理函数,
    • will 函数在进入状态之前调用;
    • did 函数在进入状态之后调用,三种状态共计五种处理函数。
      • componentWillMount()
      • componentDidMount()
      • componentWillUpdate(object nextProps, object nextState)
      • componentDidUpdate(object prevProps, object prevState)
      • componentWillUnmount() // mount 小写 (哈哈找过一次bug找了好久。)
    • 此外,React 还提供两种特殊状态的处理函数。
      • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
      • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

react生命周期执行顺序

1. getDefaultProps(),调用1次
2. getInitialState(),调用1次
3. componentWillMount(),调用1次
4. render(),调用>=1次
5. componentDidMount():仅客户端,调用1次
6. componentWillReceiveProps(object nextProps),调用>=0次
7. ShouldComponentUpdate(object nextProps, object nextState),调用>=0次
8. componentWillUpdate(object nextProps, object nextState),调用>=0次
9. render(),调用>=1次
10. componentDidUpdate(object prevProps, object prevState),调用>=0次
11. componentWillUnmount(),调用1次

事件与数据的双向绑定

栗子: react-music-player中progress组件

1
2
3
4
5
6
7
8
9
10
11
12
progress组建中:
changeProgress(e){
let progressBar = this.refs.progressBar;
let progress = (e.clientX - progressBar.getBoundingClientRect().left) /progressBar.clientWidth;
this.props.onProgressChange && this.props.onProgressChange(progress);
}
<div className="components-progress" ref="progressBar" onClick={this.changeProgress.bind(this)}>
player组件中:
progressChangeHandler(progress) {
$('#player').jPlayer(this.state.isPlay?'play':'pause', duration*progress);
}
<Progress progress={this.state.progress} onProgressChange={this.progressChangeHandler.bind(this)} />
  • 点击进度条触发progress中changeProgress事件,执行this.props.onProgressChange(progress),于是在父组件中执行
    progressChangeHandler(progress)来改变progress(父组件中state属性)

  • 父组件向子组件传递参数

  • {…this.props},{…this.state} 向子孙组件传递所有参数 …为es6用法。

  • bind(this)为es6写法,不然会报错

react input的onChange()与onBulr()

react-mixin

1
2
3
4
5
6
7
var reactMixin = require('react-mixin');
var someMixin = require('some-mixin');
class Foo extends React.Component {
render: function(){ return <div /> }
}
reactMixin(Foo.prototype, someMixin);
reactMixin(Foo.prototype, someOtherMixin);

class兼容插件

babel-plugin-react-html-attrs,要有css-loader和style-loader
webpack 配置 react-html-attrs

css模块化

1
2
3
4
5
webpack:
{ test: /\.css$/, loader: 'style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:5]' }
js:
var footer= require('./footer.css')
<Col span={20} className={footer.footer} />

:local(.normal){color:green;}
:global(.btn){color:red;}

  • 全局污染=>所有样式都是local的,解决了命名冲突和全局污染问题
  • 命名混乱=>class名生成规则配置灵活,可以此来压缩class名
  • 只需引用组件的JS就可以搞定所有的JS和CSS

  • 缺点:所有文件都要使用

css to react

将css站换成react格式
网址:https://staxmanade.com/CssToReact/

react css框架网站

网址:https://ant.design/index-cn

redux

原理图

一些react插件

下拉刷新 上拉加载更多 只支持 移动端

-------------本文结束感谢您的阅读-------------