简单粗暴react-redux基本用法

此文用最速的方法使用react-redux包,省略大量的细节,跑通使用react-redux控制的一个组件。

使用redux的基本原因,是为了保证单向数据流集中状态管理
所有的状态都保存在context中的总体状态(被称为store)里,这样所有组件都访问唯一的store。而组件本身不管理状态,只是向这个store发送action,而发送的action会被reducer处理,进而修改store。store如果被修改,则向页面发送props,令页面重新渲染(大致流向,用词不准确)。如此,数据流成为了单一的循环,避免了组件之间互相通信,也避免了mvc中的view和model通信(即页面本身绝对不会引发数据库的活动,必须派发action给管理中心store)

action
props
component
reducer
store

接下来这个例子是用react-redux操控component中一个button点击更改文字的例子:

  1. 目录下的src文件夹内文件结构为
./src
	|-- index.js
	|-- App.js
	|-- ./actions
		|-- index.js
		|-- user.js
	|-- ./reducers
		|-- index.js
		|-- user.js
  1. 在./src/index.js中
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
import App from './App';

let initialStore = {
};

const store = createStore(rootReducer, initialStore);

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

解释:

  • 首先要建立store,通过redux中createStore方法,接收两个参数,其一是rootReducer,这个reducer是所有其他reducer合并后的最终reducer;其二是initialStore,即初始化的store。
  • 随后,用react-redux库中的Provider组件包住App,并以prop的形式将store传递给其下面的所有组件。这个Provider的作用是将store置于所有组件都能访问的context中,这样就不需要在要用store的地方引入了。(为啥react不能这么搞?所有地方都要引入react)
  1. 在./actions中
    ./actions/index.js的作用是将所有actions引入
export * from "./user";

./actions/user.js中写了一个用来制造action的构造函数,这个构造函数输入一个参数名为userName,输出一个action object,包含两个key,一个为type,用来讲明action的类型,另一个为userName,即将传入的参数赋值给userName的key

export function changeUserName({ userName }) {
    return {
        type: "CHANGE_USER_NAME",
        userName: userName
    };
}

一个action就是一个object,这个object里面表达了这个action的type以及要将某一个数据a依据传入的参数变成更新后的数据a’,说白了就是一个动作肯定有一个这个动作的名字,叫type,此外,该动作就是想要依据输入参数改变某个属性的输出。

  1. 在./reducers中
    ./reducers/user.js中
const initialState = {
    username: 'alex',
}

const user = (state = initialState, action) => {
    switch (action.type) {
        case 'CHANGE_USER_NAME':
            return {
                ...state,
                username: action.userName
            }
        default:
            return state;
    }
}

export default user;

这是一个名为user的reducer,它是用来处理与user相关的action的,它作为一个函数接受两个参数,一个是state,一个是action,而它返回一个被修改后的state。可见,所谓reducer,本质上就是一个用action里面的值去替换state里面的属性值的函数,其功能相当于component里面的this.setState。
reducer的输入是原来的state和action,其返回值,就是一个修改后的state。
./reducers/index.js中

import { combineReducers } from "redux";
import user from "./user";

export default combineReducers({
    user
});

解释:从redux中引入了combineReducers方法用来把所有的reducer合并为一个reducer,这个经过合并的reducer,实际上就在根目录下的index.js文件中被引入,是用来createStore的那个rootReducer。简单来说,reducer被建立好以后就是用来createStore用的(回头看看最开始单向数据流的那张图)。
5. 在./src/App.js中

import React from 'react';
import { connect } from 'react-redux';
import { changeUserName } from './actions';

class App extends React.Component {
  changeUserName = () => {
    const { changeUserName } = this.props;
    changeUserName({
      userName: "bruce"
    })
  }

  render() {
    const { username } = this.props;
    console.log(this.props)
    return (
      <>
        <h1>{username}</h1>
        <button type="button" onClick={this.changeUserName}>change</button>
      </>
    )
  }
}

function mapStateToProps(state) {
  const { user } = state;
  return {
    username: user.username,
  }
}

export default connect(mapStateToProps, { changeUserName })(App);

解释:App中最关键的点在于connect,这个方法是从react-redux库中导入的。具体实现的机制不谈,这里要记住的是:
App能够从props里面得到当前的state依靠的是第一个函数mapStateToProps,我个人感觉理解react-redux最难的点就在这个connect上,这个connect本质上把两个object合并成了props这个object。前面一个object是mapStateToProps,即将state中的属性值取出变成this.props中要用的属性值。而在当前的state里面,其数据结构是state = {reducer名:{属性名:属性值}}。而connect的第二个参数则是传入另一个{},这个object里面将放入action creator也就是要使用的action的构造函数。其结果就是现在的this.props里面既包含了从state放下来的数据,又包含了action的构造函数,也就是把改造数据用的工具都囊括在connect里面。
最后,从this.props里面可以取出action的构造函数,在点击事件触发的函数里面,用构造函数生成一个action的实例。当点击事件发生时,这个action就被创建,然后就会因此改变store;另外从this.props里面还能够取出username(已经经过mapStatetoProps处理),这个值将被运用于页面渲染。
循环的流程始于点击事件触发action,action通过构造函数被创建,随后进入reducer修改了state,state改变引发重新渲染,mapStateToProps重新给props中的username赋值,页面重新渲染。

你可能感兴趣的:(前端)