Wscats/react-tutorial

React-Redux

Wscats opened this issue · 0 comments

高阶组件(HOC)

redux的原理是利用了高阶组件,下面就是一个常见的高阶组件,高阶组件本质是利用了函数组件和类组件的特性实现的,函数组件可以得到外部props值,并传递给类组件,然后返回类组件,最后使用的这个函数组件就是高阶组件

import React, { Component } from 'react'
export default (props) => {
    return (WraooedComponent) => {
        return class HOC extends Component {
            state = {
                name: 'Yao',
                ...props
            }
            render() {
                return (
                    <div>
                        Hello World
                        <WraooedComponent name={{...this.state}} />
                    </div>
                )
            }
        }
    }
}

在其他组件中使用该高阶组件HOC()(App)

import React, { Component } from 'react'
import HOC from './components/HOC'
class App extends Component {
  render() {
    return ( )
  };
}

export default HOC({
  age: 18
})(App);

安装

在项目目录下安装这两个模块

npm install --save react-redux
npm install --save redux

引入模块

App.jsx文件中引入

//redux
import {Provider, connect} from 'react-redux';
import {createStore} from 'redux';

配置Action

// Action
const increaseAction = {
  type: 'increase'
}

const multiAction = {
  type: 'multi'
}

配置Reduce

在这里可以灵活运用...运算符或者Object.assign()

Object.assign()方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

谨记永远不要修改state,而是返回一个全新的state

// Reducer
function counter(state = {
  count: 0
}, action) {
  const count = state.count
  switch (action.type) {
    case 'increase':
      return {
        ...state,
        count: count + 2
      }
    case 'multi':
      return Object.assign({}, state, {name: action.name});
    default:
      return state
  }
}

创建store

// Store
const store = createStore(counter);

配置Connect

语法

作用:连接React组件与 Redux store

connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])

mapStateToProps

mapStateToProps(state, ownProps)

这个函数允许我们将store中的数据作为props绑定到组件上

  1. 这个函数的第一个参数就是 Redux 的 store,你不必将 state 中的数据原封不动地传入组件,可以根据 state 中的数据,动态地输出组件需要的(最小)属性,也就是说我们可以按需返回我们需要的store数据
  2. 函数的第二个参数 ownProps,是组件自己的 props,有的时候,ownProps也会对其产生影响。

当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps,(在与 ownProps merge 后)更新给组件

mapDispatchToProps

mapDispatchToProps(dispatch, ownProps)

connect 的第二个参数是 mapDispatchToProps,它的功能是,将action作为props绑定到组件上

[mergeProps],[options]

不管是 stateProps还是dispatchProps,都需要和ownProps合并之后才会被赋给组件,所以组件既有state数据也有action方法,connect 的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect 就会使用Object.assign替代该方法

[options] (Object) 如果指定这个参数,可以定制 connector 的行为。一般不用

首先connect之所以会成功,是因为Provider组件:

  1. 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
  2. 接收Redux的store作为props,通过context对象传递给子孙组件上的connect
// Map Redux state to component props
function mapStateToProps(state) {
  return {
    value: state.count
  }
}

// Map Redux actions to component props
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => dispatch(increaseAction)
  }
}

// Connected Component
const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

在主文件main.js的集中写法

import React from 'react';
import ReactDOM from 'react-dom';
import 'react-bootstrap';
import Basic from "./components/basic.jsx";

//redux
import {Provider, connect} from 'react-redux';
import {createStore} from 'redux';

// Action
const increaseAction = {
  type: 'increase'
}

const multiAction = {
  type: 'multi'
}

// Reducer
function counter(state = {
  count: 0
}, action) {
  const count = state.count
  switch (action.type) {
    case 'increase':
      return {
        count: count + 2
      }
    case 'multi':
      return {
        count: count * 2
      }
    default:
      return state
  }
}

// Store
const store = createStore(counter);
// Map Redux state to component props
function mapStateToProps(state) {
  return {value: state.count}
}

// Map Redux actions to component props
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => {
      //可以触发多个
      dispatch(increaseAction)
      dispatch(multiAction)
    }
  }
}

// Connected Component
const App = connect(mapStateToProps, mapDispatchToProps)(Basic)

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

Basic组件

import React from 'react';
import {BrowserRouter as Router, Route, Link, browserHistory} from 'react-router-dom'
//引入组件
import Home from "./home.jsx";
import Topics from "./topics.jsx";
import About from "./about.jsx";

// React component
class Basic extends React.Component {
  render() {
    const {value, onIncreaseClick} = this.props
    return (
      <Router history={browserHistory}>
        <div>
          <p>{value}</p>
          <button onClick={onIncreaseClick}>Increase</button>
          <ul>
            <li>
              <Link to="/">首页</Link>
            </li>
            <li>
              <Link to="/about">关于</Link>
            </li>
            <li>
              <Link to="/topics">主题列表</Link>
            </li>
          </ul>
          <hr/>
          <Route exact path="/" component={Home}/>
          <Route path="/about" component={About}/>
          <Route path="/topics" component={Topics}/>
        </div>
      </Router>
    )
  }
}

export default Basic;

组件通信

通过connect方法生成新的组件,让新的组件有权利访问和修改store中的数据,从而完成组件间的数据通信

import React from 'react';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
import {connect} from 'react-redux';
class Topics extends React.Component {
  render() {
    console.log(this)
    const {value, onIncreaseClick} = this.props;
    return (
      <div>
        <h2>主题列表</h2>
        <p>{value}</p>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>
    )
  }
}

// Action
const increaseAction = {
  type: 'increase'
}
const multiAction = {
  type: 'multi'
}
// Map Redux state to component props
function mapStateToProps(state) {
  return {value: state.count}
}
// Map Redux actions to component props
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => {
      //可以触发多个
      dispatch(increaseAction)
      dispatch(multiAction)
    }
  }
}

// 最重要就是这句Connected Component让Topics也连接上store
module.exports = connect(mapStateToProps, mapDispatchToProps)(Topics);

参考案例

  1. react-redux-connect-demo
  2. simplest-redux-example
  3. React-redux中文文档

常见问题

  1. Can only update a mounted or mounting component问题