---
# System prepended metadata

title: '[Web] Route | React 與 Redux 整合'

---

# [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。