React技术栈整套工程化流程

写这篇文章的动力有两个:一个是我在 github 上的 redux-async-demo 获得了出乎意料的star数(虽然不多,但也是对我自己莫大的鼓励);另一方面,在有了一定的项目经验之后,想对整个流程再梳理一遍,方便自己日后进行参考。

一、目录结构:

目录结构

关于 Dumb 组件(纯组件)和 Smart 组件(业务组件)的划分,请参考 React.js 小书:Smart 组件 vs Dumb 组件。说实话,刚开始学 React 的时候,对这些概念都不是很理解,后来,当我自己完全接手一个大项目,尝试着去运用的时候,才真正明白这种组件划分真的是 amazing!

二、模块间调用关系

模块间调用关系

(1)入口:app.js

app.jsx 为启动入口,配置好 Thunk/Saga,将 store 传入业务组件 (/container/index.jsx)

// app.js
import '../asset/css/style.scss';
import 'antd/dist/antd.min.css';
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import createSagaMiddleware from 'redux-saga';
import axios from 'axios';

import appReducer from './redux/reducer';
import App from './container';
import rootSaga from './redux/sagas';

const sagaMiddleware = createSagaMiddleware();
const middlewares = [thunk, sagaMiddleware, logger];

const store = createStore(appReducer, applyMiddleware(...middlewares));
sagaMiddleware.run(rootSaga);

render(
    
        
    ,
    document.getElementById('app')
);

(2)业务组件 vs 纯组件

(/container/index.jsx)为 container 中的业务组件入口,专门用来获取异步数据,这样就可以跟 component 中的纯组件解耦;

component 中的组件不用关心外部的情况,只需要关注传入的 props 进行渲染即可。

每个 Smart 组件跟 Dumb 组件都通过 connect 传递 props:通过 mapStateToProps 传递 state,通过 mapDispatchToProps 传递 dispatch。

如:

import { connect } from 'react-redux';
import axios from 'axios';

import { GET_POSTS_SAGA } from 'constant/actionTypes';
import PostList from 'component/PostList';

const mapStateToProps  = (state) => ({
    posts: state.posts.posts
});

const mapDispatchToProps = (dispatch) => ({
    fetchPosts: () => dispatch({ type: GET_POSTS_SAGA })
});

export default connect(mapStateToProps, mapDispatchToProps)(PostList);

(3)两种异步流处理方式

Thunk 处理流程 ☟

Thunk 直接在业务组件中 dispatch 一个函数来异步获取数据。

/container/UserList.js

import { connect } from 'react-redux';
import axios from 'axios';

import UserList from 'component/UserList';

import { 
    GET_USERS_SUCESS, 
    GET_USERS_FAIL 
} from 'constant/actionTypes';

import {
    GET_USERS_URL
} from 'constant/url';

const mapStateToProps  = (state) => ({
    users: state.users
});

const mapDispatchToProps = (dispatch) => ({
    fetchUsers: () => {
        dispatch(() => {
            axios.get(GET_USERS_URL)
                .then((response) => {
                    dispatch({ type: GET_USERS_SUCESS, users: response.data })
                })
                .catch((error) => {
                    dispatch({ type: GET_USERS_FAIL, error })
                })
        })
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(UserList);
Saga 处理流程 ☟

Saga 在业务组件中 dispatch 一个获取数据的 action 命令,然后 saga 监听到该 action 之后再去获取数据。

/container/PostList.js

import { connect } from 'react-redux';
import axios from 'axios';

import { GET_POSTS_SAGA } from 'constant/actionTypes';
import PostList from 'component/PostList';

const mapStateToProps  = (state) => ({
    posts: state.posts
});

const mapDispatchToProps = (dispatch) => ({
    fetchPosts: () => dispatch({ type: GET_POSTS_SAGA })
});

export default connect(mapStateToProps, mapDispatchToProps)(PostList);

/redux/sagas/index.js

import { takeEvery, takeLatest } from 'redux-saga';
import { call, put } from 'redux-saga/effects';
import axios from 'axios';

import { 
    GET_POSTS_SAGA, 
    GET_POSTS_SUCCESS, 
    GET_POSTS_FAIL 
} from 'constant/actionTypes';

import {
    GET_POSTS_URL
} from 'constant/url';

// worker saga
function* showPostsAsync(action) {
    try {
        const response = yield call(axios.get, GET_POSTS_URL);
        yield put({ type: GET_POSTS_SUCCESS, posts: response.data });
    } catch(e) {
        yield put({ type: GET_POSTS_FAIL, error: e });
    }
}

// watcher saga
function* watchGetPosts() {
    yield takeLatest(GET_POSTS_SAGA, showPostsAsync);
}

// root saga
export default function* rootSaga() {
    yield watchGetPosts()
}

(4)Reducer 进行状态处理,返回新的 state

ThunkSaga 在异步获取数据之后都会再 dispatch 一个 action,然后,reducer 根据原有的 state 和 该 action 返回新的 state

(previousState, action) => newState

The End.

Demo:03_redux-router-v4-optimize

你可能感兴趣的:(React技术栈整套工程化流程)