6

以下文章均为个人近期所学心得,自学react、redux,逐渐找到自己的方向,现将自己的方向方式写出来,以供大家学习参考,肯定会有不足,欢迎批评指正。

日常项目直接使用react是完全没有问题的,可是随着项目的日益壮大,组件数量的逐渐增长,组件之间的嵌套使得数据的管理越来越繁重。
纯react项目,每个组件自己维护自己的state,父子组件之间通信、兄弟组件通信也都可以做到,只不过随时项目代码量的增加后期会变得难以维护,所以使用redux这种数据管理是很有必要的,而且也是自我技术水平提高的一个很好方向。

本文专注功能实现、使用流程,所以可能细节问题点阐述的不够深,不过个人觉得用于初学者使用并且达到想要的功能应该可以满足了。

首先原理(纯白话):
页面操作(点击啊什么的)触发action -->
action做一层处理后触发reducer -->
reducer中定义全局的唯一的store中的state+存入的方法(必须是纯函数,也就是说你传入什么参数就输出相应的结果,不可以根据实时时间戳啊等类似的方法产出不同的值。) -->
最后数据保存进了store中的state,页面也会根据state的改变自动更新。

基本:
Provider:具体概念不赘述,想细研究的自行度娘,这里只说明放在根组件的最外层并将store传递进去
    <Provider store={store}>
        <Component />
    </Provider>

代码(登录功能流程):


// 使用react-redux中的connect方法
import { connect } from 'react-redux';
// 导入我们定义的action
import { saveUserinfo } from '@/Reducers/Pages/actions';
// 使用connect包裹我们的state和action,这里有两个方法(mapStateToProps、mapDispatchToProps),具体概念自行度娘
// 组件结尾导出处
export default connect(mapStateToProps, mapDispatchToProps)(Login);
// 可以写成
export default connect(state => ({
    // 如果你的组件需要使用store中的state,就在这里引入你所以要使用的reducer函数名
}), {
    // 这里引用你当前组件所需要使用的所有action方法
    saveUserinfo
})(Login);

// 按钮提供一个点击事件
<button onClick={this.sumitForm}>登录</button>

// sumitForm方法
sumitForm = () => {
    var username = this.refs.username.value;
    var password = this.refs.password.value;
    // 发送ajax请求,这里我封装一层,很简单,可以直接写ajax请求,主要点在请求成功的回调里
    LoginFunc(username,password)
        .then(res => {
            // 请求成功后的数据
            var data = res.data;
            // 这里就是触发action的地方,只需要将我们需要的数据作为参数传进去就好
            this.props.saveUserinfo(data);
            this.props.history.push("/index");
        })
}

以上就是我们在组件中触发action的过程,到这里你就可以将接口返回来的数据传递给action了

// 定义action时需要先定义action-type,作用就是关联action和reducer,action想要触发reducer那么只需要使用定义的type就可以,不需要去引用reducer,这样别人在看我们的代码时,看type就知道这一块有哪些功能了,具体的注释也可以写在type中。
// type很简单
// 保存用户信息
export const SAVEUSERINFO = "SAVEUSERINFO";

action代码

// 导入type
import * as Pages from './action-types';
// 保存用户表单数据
export const saveUserinfo = (data) => {
    // 这个传进来的data就是我们刚刚在组件中传递进来的后端返回数据
    // 这里直接returntypes,并将data传递过去
    return {
        type: Pages.SAVEUSERINFO,
        data
    }
}

这里就是action,我们可以将组件中的后端请求写在action里,只需要返回的时候触发type并将数据传递过去就好

下面我们看reducer

// 之前说了,action只需要触发type就可以触发reducer了
// 所以reducer中同样需要引入reducer
import * as Pages from './action-types';
// 在reducer中我们需要定义state,也是就是唯一store中的state
let defaultValue = {
    session_id: "",
    user_name: "",
    user_id: "",
    is_login: false,
    initialization: "",
    org_name: ""
}
// reducer中就是将action传递过来的数据保存到store中的state里
// 两个参数,第一个是state,第二个是action传递过来的数据,包含type和数据,通过type值判断执行那个函数,这里只定义了一个type
export default function UserInfo (state = defaultValue, action = {}) {
    switch (action.type) {
        // 这个就是type也就是action和reducer关联的type
        case Pages.SAVEUSERINFO:
            return { ...state,
                // 这里就是将action传递过来的数据保存到我们的store中
                ...{
                    session_id: action.data.data.session_id,
                    user_name: action.data.data.name,
                    user_id: action.data.data.id,
                    is_login: true,
                    initialization: action.data.data.initialization,
                    org_name: action.data.data.org_name
                }
            };
        default:
            return state;
    }
}

以上就完成了我们从后端拿数据,保存到store中的所有流程。

// 保存到了store中后,我们页面的所有组件都可以拿这里边的数据,
// 同样,我们组件中用到数据的地方会根据store中数据的改变而改变,也就是说我们想要改变页面的状态,唯一的办法就是触发action完成以上步骤。

到这里我们还没有结束,需要我们形成闭环,也就是怎么将store存入我们的Provider

// 我这里是将store拆分了,按功能去拆分的,具体可以看每个人的习惯去拆分

我的目录结构,可根据具体项目区自定自己的目录结构
clipboard.png

// 有拆分就要有合并,所以我们要在存入Provider之前进行reducer的合并
// 这里使用redux提供的方法combineReducers
import {
    combineReducers,
} from 'redux';
import UserInfo from './Pages/reducers';
const rootReducer = combineReducers({ 
    UserInfo,
    // 一些其他功能的reducer
    // UserStaffDirectory,
    // addUserMsgReducer
});
// 导出统一的reducer
export default rootReducer;

插一句,以上就已经完成了基本功能,这里我在多加一项功能,就是数据持久化,也就是我们数据存到store中但是会存在一个刷新数据丢失的问题,这样很不利与我们项目的使用,所以我加入一个新的库,来保证我们的数据是可持久化的,这里使用redux-persist库
数据持久化

// 首先导入redux的一些方法
import {
    createStore,
    applyMiddleware
} from 'redux';
// 还使用了thunk,还没来的及去研究,这里先使用吧
import thunk from 'redux-thunk';
// 引入redux-persist
import { persistStore, persistReducer } from 'redux-persist';
import { PersistGate } from 'redux-persist/es/integration/react';
import storage from 'redux-persist/es/storage'
// 首先定义一个对象(按官方文档来的,没具体研究)
const persistConfig = {
    key: 'root',
    storage,
};
// 将我们的合并后的reducer引入
import Reducers from '@/Reducers';
// 使用redux-persist合并
const persistedReducer = persistReducer(persistConfig, Reducers)
// 定义一个函数,返回persistor和store,让我的组件使用
function configureStore(){
    // 这里我使用了thunk,具体原理我也没去细研究,使用redux的createStore去合并,最终产出我们需要传入Provider的store
    let store = createStore(persistedReducer, applyMiddleware(thunk));
    // 这里就是应用redux-persist以完成数据持久化
    let persistor = persistStore(store);
    return { persistor, store }
}
// 组件render中
const render = Component => {
    // 引入
    const { persistor, store } = configureStore();
    ReactDOM.render(
        // 将store传入跟组件
        <Provider store={store}>
            // 数据持久化
            <PersistGate persistor={persistor}>
                // 所有子组件
                <Component />
            </PersistGate>
        </Provider>,
        document.getElementById('app'),
    )
}

以上就完成了全部循环,组件发起action,触发reducer,保存数据到store中,组件被更新。

只有存的步骤,不能没有取,对吧,上文中实现了登录功能,并且将后端返回的数据保存到store中,现在我们将store中的数据拿出来展示在界面上。
登录请求成功后后端会返回用户名,用户ID等信息,我们已经将其保存到了store中,下面看我们的header组件将引用我们store中的用户名。

不需要我们引入过多的文件,只需要在组件结尾处的方法mapStateToProps加入我们要的reducer函数名即可

const mapStateToProps = state => ({
    UserInfo: state.UserInfo
})
export default connect(mapStateToProps,({}))(Header);
// 组件中使用
this.props.UserInfo.user_name
// 即可取值
// 同时呢,我们改变了store中的user_name那么我们取值的地方也会动态更新。

以上就是本文全部内容,如有发现不足,或错误之处,烦请指正。
转载请注明出处,SF大洋首发。


liuyang
209 声望13 粉丝

前端菜鸟一枚,爬坑ing...