事件处理

1,注意事项

  • React事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果是用jsx的语法需要穿一个函数作为事件处理函数,而不是一个字符串

    1
    2
    3
    <button onClick={activateLasers}>
    Activate Lasers
    </button>
  • 在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为。你必须明确的使用 preventDefault。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function ActionLink() {
    function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
    }
    return (
    <a href="#" onClick={handleClick}>
    Click me
    </a>
    );
    }
  • ES6 class语法定义组件,事件处理器会成为类的一个方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Toggle extends React.Component {
    constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
    this.setState(prevState => ({
    isToggleOn: !prevState.isToggleOn
    }));
    }
    render() {
    return (
    <button onClick={this.handleClick}>
    {this.state.isToggleOn ? 'ON' : 'OFF'}
    </button>
    );
    }
    }

2,向事件处理程序传递参数

  • 下面两种方式是等价的,分别通过 arrow functions 和 Function.prototype.bind 来为事件处理函数传递参数。

    1
    2
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
  • 箭头函数必须显示传递e, bind方式要隐示传递

  • 通过bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Popper extends React.Component{
    constructor(){
    super();
    this.state = {name:'Hello world!'};
    }
    preventPop(name, e){ //事件对象e要放在最后
    e.preventDefault();
    alert(name);
    }
    render(){
    return (
    <div>
    <p>hello</p>
    {/* Pass params via bind() method. */}
    <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
    </div>
    );
    }
    }

Redux

1, 介绍

  • Store
  • State
  • Action
  • Action Creator
  • store.dispatch()
  • Reducer
  • store.subscribe()

2, 工作流程

  • 首先,用户发出 Action

    1
    store.dispatch(action);
  • 然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。

    1
    let nextState = todoApp(previousState, action);
  • State 一旦有变化,Store 就会调用监听函数。

    1
    store.subscribe(listener)
  • 可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。

    1
    2
    let newState = store.getState();
    component.setState(newState);

参考[http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html]

3,组件拆分和react-redux、Provider、connect(连接器)

  • 在组件开发中,按职责我们可以划分:容器类组件、展示类组件,前者负责从state获取属性,后者负责渲染界面和自身的状态控制。
  • react-redux 为 React 组件和 Redux 提供的 state 提供了连接。当然可以直接在 React 中使用 Redux:在最外层容器组件中初始化 store,然后将 state 上的属性作为 props 层层传递下去。但是这样并是我们推荐的状态管理方式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class App extends Component{
    componentWillMount(){
    store.subscribe((state)=>this.setState(state))
    }
    render(){
    return <Comp state={this.state}
    onIncrease={()=>store.dispatch(actions.increase())}
    onDecrease={()=>store.dispatch(actions.decrease())}/>
    }
    }
  • 我们推荐的方式是react-redux:1,内容组件最外层包裹Provider,将之前创建的store作为prop传给Provider。Provider接收redux的createStore()的结果,并且放到context里,让子组件可以通过context属性直接获取到这个createStore的结果。且返回一个与store连接后的容器组件。2,Provider内的任何一个组件,如果需要使用state中的数据,就必须是「被 connect 过的」组件——使用connect方法对当前内容组件包装后的产物,connect会返回一个与store连接后的新组件。3,connect会返回一个与store连接后的新组件。会接收到mapStateToProps,会在内部subscribe全局state的改变,来判断props是否更改,如果需要更新,才触发更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as dictActions from '../../actions/dict';

class DictPage extends Component {
constructor(props){
super(props);

}
componentWillMount(){
const { getDictsResult } = this.props;
getDictsResult({
q: 'good',
lang: 'en'
})
}
componentDidMount(){
const { dict } = this.props;
}
render() {
return (<div>xxxxx</div>);
}
}
//创建输入逻辑mapStateToProps,是store、state映射
function mapStateToProps(state) {
return {
dict: state.dict.data.data
};
}

//输出逻辑mapDispatchToProps,是dispatch映射
function mapDispatchToProps(dispatch) {
return bindActionCreators(dictActions, dispatch);
}

//把容器组件和ui组件结合导出
export default connect(mapStateToProps, mapDispatchToProps)(DictPage);

参考例子

React-router(v4版本)

1, 包的选择

  • 浏览器用的router在react-router-dom里。所以浏览器里使用的时候只需要import react-router-dom就可以。react-router-native供React Native应用使用。

2,路由不在集中存放一起,可以和Ui组件放在一起,成为组件的一部分。

3,包含式路由与exact

  • 如匹配 path=”/users” 的路由会匹配 path=”/“的路由,在页面中这两个模块会同时进行渲染,所以就多了exact。

4,独立路由Switch

  • 采用Switch 只有一个路由会被渲染,并且总是渲染第一个匹配到的组件。
  • to(string / object):要跳转的路径或地址;
  • replace :为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址。反之不会替换记录,默认为false。
  • NavLink :的一个特定版本,会在匹配上当前URL的时候会给已经渲染的元素添加样式参数。

6,异步加载路由和模块

7, 手动控制路由的跳转

  • 使用 withRouter高阶组件,提供了history让你使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import React from "react";
    import {withRouter} from "react-router-dom";

    class MyComponent extends React.Component {
    ...
    myFunction() {
    this.props.history.push("/some/Path");
    }
    ...
    }
    const MyComponent=withRouter(connect(mapStateToProps,mapDispatchToProps)(MyComponent))
    export default MyComponent;
  • 使用Context,在Router组件中通过Contex暴露了一个router对象。context增加了耦合难度尽量少用或者用在全局登录状态、颜色等等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import React from "react";
    import PropTypes from "prop-types";

    class MyComponent extends React.Component {
    static contextTypes = {
    router: PropTypes.object
    }
    ...
    myFunction() {
    this.context.router.history.push("/some/Path");
    }
    ...
    }
  • 引入Redirect,重定向。

  • 引入react-router-redux库,操作redux,进行时间旅行调试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import React from "react";
    import { push } from 'react-router-redux'
    import PropTypes from "prop-types";

    class MyComponent extends React.Component {
    static contextTypes = {
    store: PropTypes.object
    }
    ...
    myFunction() {
    this.context.store.dispatch(push('path'))
    }
    ...
    }

constructor(super(props))

constructor( )——构造方法

  • ES6对类的默认方法,new命令生成实例自动调用,如果没有显示定义会默认添加空的constructor方法。
  • es5没有继承写法,通过prototype来达到目的。

    1
    2
    3
    4
    5
    6
    7
    8
    //构造函数People
    function People (name,age){
    this.name = name;
    this.age = age
    }
    People.prototype.sayName = function(){
    return '我的名字是:'+this.name;
    }
  • ES6中,可以通过class来实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class People{
    //构造方法constructor就等于上面的构造函数People
    constructor(name,age){
    this.name = name;
    this.age = age;
    }

    sayName(){
    return '我的名字是:'+this.name;
    }
    }

super() – 继承。

  • 子类是没有自己的this对象的,它只能继承自父类的this对象,然后对其进行加工,而super( )就是将父类中的this对象继承给子类的。没有super,子类就得不到this对象

    class People{
          constructor(name,age){
              this.name = name;
              this.age = age;
          }
          sayName(){
              return '我的名字是:'+this.name;
          }
      }
    
      class har extends People{
          constructor(name,age,sex){
              super(name,age);//调用父类的constructor(name,age)
              this.sex = sex;
          }
          haha(){
              return this.sex + ' ' + super.sayName();//调用父类的sayName() 
          }
      }
    

    es5 new

  • 1.生成一个空的对象并将其作为 this;
  • 2.将空对象的 proto 指向构造函数的 prototype;
  • 3.运行该构造函数;
  • 4.如果构造函数没有 return 或者 return 一个返回 this 值是基本类型,则返回this;如果 return 一个引用类型,则返回这个引用类型。

es5和es6继承机制区别

  • es5先创建子类的实例对象this,然后再将父类的方法添加到this上( Parent.apply(this) )
  • ES6采用的是先创建父类的实例this(故要先调用 super( )方法),完后再用子类的构造函数修改this

学习文章参考