實戰react技術棧+express先後端博客項目(2)-- 前端react-xxx、路由配置

項目地址:github.com/Nealyang/Re…前端

本想等項目作完再連載一波系列博客,隨着開發的進行,也是的確遇到了很多坑,請教了很多人。遂想,何不一邊記錄踩坑,一邊分享收穫呢。分享固然是好的, 若是能作到集思廣益,那豈不是更美。咱們的口號是:堅定不會爛尾react

本博客爲連載代碼博客同步更新博客,隨着項目日後開發可能會遇到前面寫的不合適的地方會再回頭修改。若有不妥~歡迎兄弟們不嗇賜教。謝謝!git

react-redux 配置說明

reducer

首先咱們在項目/app/reducers下新建一個index.js,用於導出全部的reducer。 也用於將admin、front等reducer彙總的文件。最後combineReducers後直接導出。github

export default combineReducers({
    front,
    globalState: reducer,
    admin
})
複製代碼

上面admin,reducer,front是別的文件中的reducer處理。這裏咱們能夠暫時導出一個空的state。express

對應的每個子reducer書寫大體以下:redux

export const actionTypes = {
    ADMIN_URI_LOCATION:"ADMIN_URI_LOCATION"
};

const initialState = {
    url:"/"
};

export const actions = {
    change_location_admin:function (url) {
        return{
            type:actionTypes.ADMIN_URI_LOCATION,
            data:url
        }
    }
};

export function reducer(state=initialState,action) {
    switch (action.type){
        case actionTypes.ADMIN_URI_LOCATION:
            return {
                ...state,url:action.data
            };
        default:
            return state
    }
}

const admin = combineReducers({
    adminGlobalState:reducer,
    users,
    tags
});

export default admin
複製代碼

定義initialState(這個state節點上的initialState,不總的state),actions,actionTypes以及reducer。而後倒入reducer。 在index中引入後,即爲state中的admin節點。後端

configureStore

配置store的文件。這個文件的功能正如其名,就是配置store的。其中咱們主要作了以下工做。微信

  • applyMiddleware->將一些中間件、reducer、裝在進去
  • 區分環境,判斷是否須要加入開發工具。如:devToolsExtension
  • 配合熱更新
  • createStore

代碼以下:session

const win = window;
const sagaMiddleware = createSagaMiddleware();
const middlewares = [];

let storeEnhancers ;
if(process.env.NODE_ENV==='production'){
    storeEnhancers = compose(
        applyMiddleware(...middlewares,sagaMiddleware)
    );
}else{
    storeEnhancers = compose(
        applyMiddleware(...middlewares,sagaMiddleware),
        (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
    );
}

export default function configureStore(initialState={}) {
    const store = createStore(rootReducer, initialState,storeEnhancers);
    sagaMiddleware.run(rootSaga);
    if (module.hot && process.env.NODE_ENV!=='production') {
        // Enable Webpack hot module replacement for reducers
        module.hot.accept( './reducers',() => {
            const nextRootReducer = require('./reducers/index');
            store.replaceReducer(nextRootReducer);
        });
    }
    return store;
}
複製代碼

最後倒入store,用於在App中使用。react-router

react-router 配置說明

react-router中的配置主要在/container/index.js文件中。該文件負責導出全部路由中的文件。

說一下該項目的路由大體規則。默認狀況下,輸入域名(咱們這裏是localhost),直接進入首頁。也就是咱們項目中的front部分。

/ -> 首頁 (雖說首頁,可是仔細看頁面結構,其實就是文章列表頁)
/:tag -> 其餘文章列表頁
/detail/:id -> 詳情頁
/admin -> 後臺管理首頁
/admin/xxx -> 後臺管理頁的某一個模塊 好比:/admin/managerTags -> 標籤管理頁面
/404 -> notFound 
複製代碼

因此根據路由配置先具體後模糊的規則。而且這裏牽涉到路由嵌套,因此一定抽離出組件來:

index.js render部分以下:

render() {
        let {isFetching} = this.props;
        return (
            <Router>
                <div>
                    <Switch>
                        <Route path='/404' component={NotFound}/>
                        <Route path='/admin' component={Admin}/>
                        <Route component={Front}/>
                    </Switch>
                    {isFetching && <Loading/>}
                    {this.props.notification && this.props.notification.content ?
                        (this.props.notification.type === 1 ?
                            this.openNotification('success', this.props.notification.content) :
                            this.openNotification('error', this.props.notification.content)) :
                        null}
                </div>
            </Router>
        )
    }
複製代碼

由於路由模糊的部分只要front部分是最模糊的,因此咱們把它匹配到最下面。別的你們應該都沒有疑惑,至於isFetch notification後面會介紹。 至於爲何要在這裏放這些isFetch和notification。由於這是全部路由的最外面一層,是front和admin界面下公共的部分。Loading加載圖標,全局提示信息均可以公用。 因此咱們放在最外層。

必定記住。能公用的一組東西,咱們必定是放到路由匹配的最外層。

下面看下Font和admin的代碼

const Front = ({match}) => {
    return (
        <div>
            <div className={`${animationStyle.animated} ${animationStyle.fadeInDown}`}>
                <Banner/>
                <Menus/>
            </div>
            <Switch>
                <Route exact path={match.url} component={Home}/>
                <Route path={`/detail/:id`} component={Detail}/>
                <Route path={`/:tag`} component={Home}/>
                <Route component={NotFound}/>
            </Switch>
        </div>
    )
};
複製代碼

admin:

render() {
        const {url} = this.props.match;
        if(this.props.userInfo.userType){
            return (
                <div>
                    {
                        this.props.userInfo.userType === 'admin' ?
                            <div className={style.container}>
                                <div className={style.menuContainer}>
                                    <AdminMenu history={this.props.history}
                                               url={this.props.adminUrl}
                                               changeUrl={this.props.change_location_admin}/>
                                </div>
                                <div className={style.contentContainer}>
                                    <Switch>
                                        <Route exact path={url} component={AdminIndex}/>
                                        <Route path={`${url}/managerUser`} component={AdminManagerUser}/>
                                        <Route path={`${url}/managerTags`} component={AdminManagerTags}/>
                                        <Route path={`${url}/newArticle`} component={AdminNewArticle}/>
                                        <Route path={`${url}/detail`} component={Detail}/>
                                        <Route component={NotFound}/>
                                    </Switch>
                                </div>
                            </div> :
                            <Redirect to='/'/>
                    }
                </div>
            )
        }else{
            return <NotFound/>
        }

    }
複製代碼

注意admin中的路由匹配,這裏必需要使用{match},不然你點擊link你會發現路由跳轉成功了,可是對應頁面沒有渲染。

關於admin中爲何判斷this.props.userInfo後續權限判斷哪裏會說到。以及會說這裏遇到的一些問題(重點)。這裏咱們仍是隻關注路由部分。再次強調,必須使用match 來取url。而後根據本身後臺管理的定義項,隨着開發,日後面去填充對應的路由便可。

結束語

至此,這個項目的redux,router基本就配置完成了。後續隨着開發,回往/app/reducers中在添加對應的reducer。以及在路由中添加新建的頁面。

若是您有更好想法,歡迎您聯繫我。咱們一塊兒改進~

若是有什麼不明白的地方,歡迎提issue。我會第一時間處理。

項目實現步驟系列博客

  • 實戰react技術棧+express先後端博客項目(0)-- 預熱一波
  • 實戰react技術棧+express先後端博客項目(1)-- 總體項目結構搭建、state狀態樹設計
  • 實戰react技術棧+express先後端博客項目(2)-- 前端react-xxx、路由配置
  • 實戰react技術棧+express先後端博客項目(3)-- 後端路由、代理以及靜態資源託管等其餘配置說明
  • 實戰react技術棧+express先後端博客項目(4)-- 博客首頁代碼編寫以及redux-saga組織
  • 實戰react技術棧+express先後端博客項目(5)-- 先後端實現登陸功能
  • 實戰react技術棧+express先後端博客項目(6)-- 使用session實現免登錄+管理後臺權限驗證
  • 實戰react技術棧+express先後端博客項目(7)-- 前端管理界面用戶查看功能+後端對應接口開發
  • 實戰react技術棧+express先後端博客項目(8)-- 前端管理界面標籤管理功能+後端對應接口開發
  • 實戰react技術棧+express先後端博客項目(9)-- 前端管理界面標籤管理功能+後端對應接口開發
  • 實戰react技術棧+express先後端博客項目(10)-- 前端管理界面發表文章功能
  • 實戰react技術棧+express先後端博客項目(11)-- 後端接口對應文章部分的增刪改查
  • 實戰react技術棧+express先後端博客項目(12)-- 前端對於發文部分的完善(增刪改查、分頁等)
  • 實戰react技術棧+express先後端博客項目(13)-- 前端對於發文部分的完善(增刪改查等)
  • 實戰react技術棧+express先後端博客項目(14)-- 內容詳情頁以及閱讀數的展現
  • 實戰react技術棧+express先後端博客項目(15)-- 博客添加評論功能以及對應後端實現
  • 實戰react技術棧+express先後端博客項目(16)-- pm2 的使用說明
  • 實戰react技術棧+express先後端博客項目(17)-- 收工

學習交流

歡迎關注我的微信公衆號: Nealyang 全棧前端,獲取第一手文章推送和免費全棧電子書分享福利

相關文章
相關標籤/搜索