react一统江湖

react还是vue

我对前端没兴趣,vue和react都搞一下,vue只会vue-cli,react只会create-react-app,webpack只会抄,从来不用代码规范检查, 两条腿走路不瘸

基础

文档

  • JSX

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class App extends Component {
    render() {
    return (
    <div>
    <h1>嘿嘿嘿...</h1>
    </div>
    );
    }
    }
    export default App;
  • 数据OR状态

    1
    2
    3
    4
    5
    6
    constructor(props) {
    super(props)
    this.state = {
    .....
    }
    }

使用: this.state.xxx this.props.xxx

  • props校验
    参考文档

    React.PropTypes已经废弃, 使用prop-types

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import PropTypes from 'prop-types'

    MyComponent.propTypes = {
    // 你可以将属性声明为以下 JS 原生类型
    optionalArray: PropTypes.array,
    optionalBool: PropTypes.bool,
    optionalFunc: PropTypes.func,
    optionalNumber: PropTypes.number,
    optionalObject: PropTypes.object,
    optionalString: PropTypes.string,
    optionalSymbol: PropTypes.symbol,
    ....

属性默认值:

1
2
3
4
// 为属性指定默认值:
MyComponent.defaultProps = {
name: 'Stranger'
};

  • 组件API

    1
    this.setState({...})
  • 生命周期

    1. 装配, 在组件实例被创建和插入DOM中时被调用:

      1
      2
      3
      4
      5
      constructor()
      static getDerivedStateFromProps()
      componentWillMount() / UNSAFE_componentWillMount()
      render()
      componentDidMount()
    2. 更新,属性或状态的改变会触发一次更新

      1
      2
      3
      4
      5
      6
      7
      componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
      static getDerivedStateFromProps()
      shouldComponentUpdate()
      componentWillUpdate() / UNSAFE_componentWillUpdate()
      render()
      getSnapshotBeforeUpdate()
      componentDidUpdate()
    3. 卸载,组件被从DOM中移除时

      1
      componentWillUnmount()
    4. 错误,渲染过程中发生错误时

      1
      componentDidCatch()
  • 表单

    1. 数据绑定 {this.state.data}
    2. 输入事件监听 onChange
    3. select选中状态处理

      1
      2
      3
      4
      5
      6
      <select value={this.state.value} onChange={this.handleChange}>
      <option value="grapefruit">Grapefruit</option>
      <option value="lime">Lime</option>
      <option value="coconut">Coconut</option>
      <option value="mango">Mango</option>
      </select>
    4. 多个表单设置state

      1
      2
      3
      this.setState({
      [name]: value
      });
  • 路由

    1
    2
    react-router: 路由核心功能
    react-router-dom: 基于react-router进行了拓展, 一般import这个即可

结构

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
import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Home from './Home';
import Login from './Login';

class App extends Component {
render() {
return (
<Router>
<div>
<h2>xxxxx</h2>
<ul>
<li><Link to={'/'}>Home</Link></li>
<li><Link to={'/Login'}>Login</Link></li>
</ul>
<hr />

<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/Login' component={Login} />
</Switch>
</div>
</Router>
);
}
}
export default App;

  • 高阶组件

    接收组件作为参数, 对组件功能 数据进行扩展, 有点像装饰模式

    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
    import React from 'react';

    var newData = {
    data: 'Data from HOC...',
    }

    var MyHOC = ComposedComponent => class extends React.Component {

    componentDidMount() {
    this.setState({
    data: newData.data
    });
    }

    render() {
    return <ComposedComponent {...this.props} {...this.state} />;
    }
    };


    class MyComponent extends React.Component {
    render() {
    return (
    <div>
    <h1>{this.props.data}</h1>
    </div>
    )
    }
    }

    export default MyHOC(MyComponent);

路由React Router

中文文档

  • HashRouter和BrowserRouter
    最外层Router, 属性: basename
  • Route

    Route是路由的一个原材料,它是控制路径对应显示的组件。我们经常用的是exact、path以及component属性
    path: /user/:id ,支持参数占位符
    Route多级路由可以嵌套使用
    IndexRoute 设置默认组件
    重定向

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <Router>
    <Route path="/" component={App}>
    <IndexRoute component={Dashboard} />
    <Route path="about" component={About} />
    <Route path="inbox" component={Inbox}>
    {/* 使用 /messages/:id 替换 messages/:id */}
    <Route path="/messages/:id" component={Message} />
    </Route>
    </Route>
    </Router>
  • Link和NavLink

    都是控制路由跳转, NavLink API更多

    1. to: 接收string或者object,控制跳转的url,参数等
    2. NavLink支持activeClassName, exact等属性
    3. exact: 严格匹配
    4. IndexLink: 如果需要在 Home 路由被渲染后才激活的指向 / 的链接,请使用 Home
  • match

    match是在使用router之后被放入props中的一个属性,在class创建的组件中我们需要通过this.props.match来获取match之中的信息

  • Switch

    Switch常常会用来包裹Route,它里面不能放其他元素,用来只显示一个路由

  • hook钩子函数
    1. onEnter
    2. onLeave
  • 路由匹配
    1. :paramName – 匹配一段位于 /、? 或 # 之后的 URL。 命中的部分将被作为一个参数

      path=”/hello/:name”

    2. () – 在它内部的内容被认为是可选的

      path=”/hello(/:name)”
      path=”/order/:direction(asc|desc)” “/order/asc”–> matched “/order/desc”–>matched

    3. * – 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数

      path=”/files/*.*“ // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg

  • withRouter

    withRouter(MyComponent) 向组件poops传递match ,location,history三个属性

  • nginx路由处理

    vue react都是一样的问题,也不算什么问题

    1
    2
    3
    4
    5
    6
    server {
    ...
    location / {
    try_files $uri /index.html; # try_files $uri $uri/index.html; try_files $uri $uri/ /index.html;
    }
    }

Redux 状态管理

与vuex一样的思想, 官方文档与阮一峰博客教程都很详细
官方例子:

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
40
41
import { createStore } from 'redux';

/**
* 这是一个 reducer,形式为 (state, action) => state 的纯函数。
* 描述了 action 如何把 state 转变成下一个 state。
*
* state 的形式取决于你,可以是基本类型、数组、对象、
* 甚至是 Immutable.js 生成的数据结构。惟一的要点是
* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
*
* 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}

// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);

// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
console.log(store.getState())
);

// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1

  • store

    store 保存数据的容器, 整个应用只维护一个

    1
    2
    import { createStore } from 'redux';
    const store = createStore(fn);

createStore接收一个函数reducer作为参数,返回store对象

  • state

    store容器内保存的数据状态

    1
    2
    3
    4
    import { createStore } from 'redux';
    const store = createStore(fn);

    const state = store.getState();

redux规范里,state与view相互对应

  • action
    视图层view触发容器内state变化的唯一途径就是通过action
    1
    2
    3
    4
    const action = {
    type: 'ADD_TODO',
    payload: 'Learn Redux'
    };

action是一个对象, type表示action动作标识名称,必需. 其它属性可选

  • Action Creator

    action生成器, 通过函数生成一个action对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const ADD_TODO = '添加 TODO';

    function addTodo(text) {
    return {
    type: ADD_TODO,
    text
    }
    }

    const action = addTodo('Learn Redux');
  • dispatch

    view触发action动作的唯一方式

    1
    2
    3
    4
    5
    6
    7
    8
    import { createStore } from 'redux';
    const store = createStore(fn);

    store.dispatch({
    type: 'ADD_TODO',
    payload: 'Learn Redux'
    });
    //store.dispatch(addTodo('Learn Redux'));
  • reducer

    store容器收到action事件后 返回新的state数据状态, 这个计算过程称为reducer

    1
    2
    3
    4
    const reducer = function (state, action) {
    // ...
    return new_state;
    };

reducer是一个函数, 接收state,action作为参数, 返回新的state
reducer并不改变原始state, 而总是返回新的对象

1
2
import { createStore } from 'redux';
const store = createStore(reducer);

实际应用中, store.dispatch会自动触发reducer过程, 只需创建容器时把reducer作为参数

  • subscribe

    store.subscribe设置监听函数, state变化会自动触发这个函数

    1
    2
    3
    4
    import { createStore } from 'redux';
    const store = createStore(reducer);

    store.subscribe(listener);
  • 中间件与异步

    有机会再研究, 太累了

react-redux

redux作者提供的react操作redux库

  • UI组件
    1
    只负责UI,所有数据通过props提供, 不维护state
  • 容器组件

    1
    只负责redux数据管理, 不负责UI
  • connect

    1
    2
    import { connect } from 'react-redux'
    const VisibleTodoList = connect()(TodoList);

TodoList是 UI 组件,VisibleTodoList就是由 React-Redux 通过connect方法自动生成的容器组件
connect完整用法:

1
2
3
4
5
6
import { connect } from 'react-redux'

const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)

connect方法接受两个参数:mapStateToProps和mapDispatchToProps
它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action

  • mapStateToProps

    建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系

    1
    2
    3
    4
    5
    const mapStateToProps = (state) => {
    return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
    }
    }

    mapStateToProps是一个函数,接收state参数,返回新的state对象.
    还可以接受第二个参数,UI组件的props对象.
    getVisibleTodos是一个reducer

  • mapDispatchToProps

    定义了哪些用户的操作应该当作 Action,传给 Store容器
    mapDispatchToProps可以是一个对象或者函数,大同小异

    1
    2
    3
    4
    5
    6
    const mapDispatchToProps = {
    onClick: (filter) => {
    type: 'SET_VISIBILITY_FILTER',
    filter: filter
    };
    }
  • provider

    connect方法生成容器组件以后,需要让容器组件拿到state对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import { Provider } from 'react-redux'
    import { createStore } from 'redux'
    import todoApp from './reducers'
    import App from './components/App'

    let store = createStore(todoApp);

    render(
    <Provider store={store}>
    <App />
    </Provider>,
    document.getElementById('root')
    )

Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了

案例: 计数器

本文标题:react一统江湖

文章作者:啪啪啪的指针

发布时间:2018年09月03日 - 10:09

最后更新:2018年09月04日 - 11:09

原始链接:https://www.bootvue.com/2018/09/03/react/

转载说明: 转载请保留原文链接及作者。