Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react / redux #118

Open
hoperyy opened this issue Aug 22, 2018 · 0 comments
Open

react / redux #118

hoperyy opened this issue Aug 22, 2018 · 0 comments

Comments

@hoperyy
Copy link
Owner

hoperyy commented Aug 22, 2018

react 基本用法

参考资料:http://www.ruanyifeng.com/blog/2015/03/react.html

import ReactDom from 'react-dom';

几种写法

  • 写法 1:纯 HTML

    const Mod = <div>Test</div>;
    
    ReactDOM.render(Mod, document.getElementById( 'app' ) )
  • 写法 2:HTML 嵌套 JavaScript({})

    const Mod = <div>{ [1, 2, 3] }</div>
    
    ReactDOM.render(Mod, document.getElementById( 'app' ) )
  • 写法 3:互相嵌套,JavaScript 中可以直接使用 HTML

    const Mod = <div>{ [ <div>1</div>, <strong>2</strong>, 3 ] }</div>;
    
    ReactDOM.render(Mod, document.getElementById( 'app' ) )
  • 写法 4:用 React.createClass 方法生成一个组件类

    const Mod = React.createClass({
        render() {
            return <h1>Hello {this.props.name}</h1>
        }
    });
    
    ReactDOM.render(<Mod name="world" />, document.getElementById( 'app' ) )

    组件类的第一个字母必须大写,否则会报错。

    组件类只能包含一个顶层标签,否则也会报错。

JSX

JSX 允许 HTML 和 JavaScript 的混写。

JSX 允许直接在模板插入 JavaScript 变量({})。如果这个变量是一个数组,则会展开这个数组的所有成员。

组件的用法与原生的 HTML 标签完全一致,可以任意加入属性。组件的属性可以在组件类的 this.props 对象上获取。

需要注意的例外

  • 添加组件属性,有一个地方需要注意,就是 class 属性需要写成 classNamefor 属性需要写成 htmlFor ,这是因为 classforJavaScript 的保留字。

  • this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点

    这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

    React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object

属性限制

var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

属性默认值

var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

ReactDOM.render(
  <MyTitle />,
  document.body
);

获取真实的 DOM

根据 React 的设计,所有 DOM 的变动,都先在虚拟 DOM 上发生,再将实际发生变动的部分应用在真实的 DOM 上。

获取真实 DOM 的方式就是加上属性 ref

组件中使用 this.ref[refName] 获取真实的 DOM。

this.state

  • 初始化状态

    getInitialState: function() {
        return {liked: false};
    },
  • 设置状态

    this.setState({liked: !this.state.liked});
  • propsstate 区别

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

生命周期

  • Mounting:已插入真实 DOM

    • componentWillMount
    • componentDidMount
  • Updating:正在被重新渲染

    • componentWillUpdate
    • componentDidUpdate
  • Unmounting:已移出真实 DOM

    • componentWillUnmount

此外,React 还提供两种特殊状态的处理函数。

  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用

  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

Redux

Redux 的设计思想

  • Web 应用是一个状态机,视图与状态是一一对应的
  • 所有的状态保存在一个对象里

Store

Store 就是保存数据的地方,一个应用只有一个 Store。

如何生成 Store 对象。

import { createStore } from 'redux';

const store = createStore(fn);

State

Store 某个时刻的数据状态,称为 state。

获取 state 的方式:

const state = store.getState();

Redux 规定,一个 State 对应一个 View。只要 State 相同,View 就相同。反之亦然。

Action

  • 原理

    State 的变化会触发 View 的变化。

    View 的变化,通过发出 Action 通知,触发 State 的变化。

  • 格式

    Action 是一个对象,其中 type 属性是必须的,表示 Action 的名称。

    其他属性可以自由设置。

  • 进一步:Action Creator

    View 要发送多少个消息,就要发出多少个 Action。手写会比较麻烦,所以可以通过函数生成 Action,叫 Action Creator。

    const ADD_TODO = 'ADD_TODO';
    
    function addTodo(text) {
        return {
            type: ADD_TODO,
            payload: text
        };
    }
    
    const action = addTodo('Learn Redux');
  • View 如何发出 Action

    store.dispatch(action)

    举例:

    const store = createStore(fn);
    
    store.dispatch(action);

Reducer

Store 接收 Action 后,经过处理,产生新的 State,View 才会变化,这个处理过程叫 Reducer。

const reducer = (state, action) => {
    ...

    return new_state;
};

整理上面的步骤

  • View 发出 Action

    store.dispatch(action);
  • 产生新 state

    const newState = reducer(state, action);
  • 新 State 触发 View 变化

  • 将上面的过程自动化:dispatch 时自动执行 reducer

    这时,store 需要知道 reducer 函数。所以这样写:

    const store = createStore(reducer);

    这样,当 View dispatch action 后,会自动触发 reducer,生成新的 state。

纯函数

纯函数的特点:同样的输入,一定是同样的输出。

因此有以下要求:

  • 不得修改参数
  • 不能调用系统 I/O 的 API
  • 不能调用 Date.now()Math.random() 等不纯的方法,因为每次都会有不同的效果

Reducer 是纯函数,就可以保证同样的 State 必定得到同样的 View。

但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象。

// State 是一个对象
function reducer(state, action) {
  return Object.assign({}, state, { thingToChange });
  // 或者
  return { ...state, ...newState };
}

// State 是一个数组
function reducer(state, action) {
  return [...state, newItem];
}

最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。

监听 Store 中 state 的变化

const store = createStore(reducer);

const unsubscribe = store.subscribe(listener);

解除监听:unsubscribe()

梳理一下

Store 提供了三个方法:

store.getState()

store.dispatch()

store.subscribe()
let { subscribe, dispatch, getState } = createStore(reducer);

createStore 还接收第二个参数,表示 State 的最初状态。注意,如果提供了这个参数,它会覆盖 Reducer 函数的默认初始值。

createStore 的实现

const createStore = (reducer) => {
    let state;
    let listeners = [];

    const getState = () => state;

    const dispatch = (action) => {
        state = reducer(state, action);

        listeners.forEach(listener => listener());
    };

    const subscribe = (listener) => {
        listeners.push(listener);

        return () => {
            listeners = listeners.filter(l => l !== listener);
        };
    };

    dispatch({});

    return { getState, dispatch, subscribe };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant