# [Web] Route | React 與 Redux 整合 Route 有 path、component 屬性,根據 URL 不同的 path ,決定現在要render哪個組件,而 Connect 則是用來將 React & Redux 整合到根組件上。接下來用註冊、登入的頁面切換解釋 Route 與 Redux 的運作 完整程式碼 **(不用看懂,後面分成小部分做重點說明)** ```sql= class Root extends React.Component { componentDidMount() { firebase.auth().onAuthStateChanged(user => { if (user) { this.props.setUser(user); this.props.history.push("/"); } else { this.props.history.push("/login"); this.props.clearUser(); } }); } render() { return this.props.isLoading ? ( <Loading /> ) : ( <Switch> <Route exact path="/" component={App} /> <Route path="/login" component={Login} /> <Route path="/register" component={Register} /> </Switch> ); } } const mapStateFromProps = state => ({ isLoading: state.user.isLoading }); const mapDispatchToProps = dispatch => { return { setUser: () => dispatch({ type: 'SET_USER' }), clearUser: () => dispatch({ type: 'CLEAR_USER' }), } } const RootWithAuth = withRouter( connect( mapStateFromProps, mapDispatchToProps )(Root) ); const store = createStore(rootReducer, composeWithDevTools()); ReactDOM.render( <Provider store={store}> <Router> <RootWithAuth /> </Router> </Provider>, document.getElementById("root") ); registerServiceWorker(); ``` --- ## Switch / Route ```javascript <Switch> <Route exact path="/" component={App} /> <Route path="/login" component={Login} /> <Route path="/register" component={Register} /> </Switch> ``` * <h3>Switch :</h3> 控制只有在第一個Route符合path才會render component,所以就算 URL path 符合十個Route 的 path ,也只會 render 第一個符合的 component * <h3>Route:</h3>根據不同 path 渲染不同的 component(exact為精準匹配模式) --- ## connect / withRouter / mapStateToProps / mapDispatchToProps ```javascript const RootWithAuth = withRouter( connect( mapStateFromProps, mapDispatchToProps )(Root) ); ``` * <h3>connect :</h3> 將 React & Redux 連結在一起, State 和 Action ( Redux ) 綁定到 Root 組件(React) * <h3>withRouter:</h3>把 react-router 的history、location、match 傳入,如果沒有withRouter,前面this.props.history.push() 就無法使用,因為 this.props.history 會變成 undefined <div style="text-align: center"> <img src="https://i.imgur.com/YpWqc3y.png"/> </div> * <h3>mapStateToProps:</h3>當 store state 改變時被呼叫,並 return 一個整合所有 state 的 object * <h3>mapDispatchToProps:</h3>dispatch action to store state,return 由很多 function 組成的 object,根據裡面不同的 function, dispatch 不同的 action ## ReactDOM.render / Provider / Router ```javascript ReactDOM.render( <Provider store={store}> <Router> <RootWithAuth /> </Router> </Provider>, document.getElementById("root") ); ``` * <h3>ReactDOM.render:</h3> 在 container 裡面 render element ```javascript ReactDOM.render(element, container[, callback]) ``` * <h3>Provider:</h3>使組件中 connect() 獲得 Redux Store,若不使用 Provider ,則須將 store 作為 props 傳入每個需要使用的組件中 * <h3>Router:</h3>以 <Router/> 包住所有的 <Route/>,類似用 div 包住 head、image、context的功用。 ### End ``` <Route exact path="/" component={AppContainer} /> ``` Redux store 透過 Provider 往下傳遞到 Route ,而 Container 則負責和 Redux store 溝通,coponent 中的 props 來自於 Container 裡面 connect (mapStateToProps, mapDispatchToProps) --- ### Others * Root Class componentDidMount fireBase會員驗證( onAuthStateChanged 等待 getResult 後再觸發接下來的 ) -> 判斷是否已經登入 -> this.props.history.push() 控制路由轉跳頁面 -> render() ### End 為了實現 SPA 在同一個頁面裡根據不同的邏輯判斷決定渲染(render)的組件,這篇分享使用 Route 實現SPA。