# Section 13 - Integrating React with Redux
# Table of Contents
- Section 13 - Integrating React with Redux
- Table of Contents
- [Lecture] React Cooperating with Redux
- [Lecture] React, Redux, and...React-Redux!?
- [Lecture] Design of the Redux App
- [Lecture] How React-Redux Works
- [Lecture] Redux Project Structure
- [Lecture] Named vs Default Exports
- [Lecture] Building Reducers
- [Lecture] Wiring Up the Provider
- [Lecture] The Connect Function
- [Lecture] Configuring Connect with MapStateToProps
- [Lecture] Building a List with Redux Data
- [Lecture] Calling Action Creators from Components
- [Lecture] Redux is Not Magic!
- [Lecture] Functional Components with Connect
- [Lecture] Conditional Rendering
- [Lecture] Exercise Solution - Connecting Components to Redux
# [Lecture] React Cooperating with Redux
首先透過腳手架工具 create-react-app 創建我們的專案:
# Initiate a project
$ create-react-app songs
# [Lecture] React, Redux, and...React-Redux!?
在我們的專案中,會有兩個主要的組件:
SongList: 顯示歌曲清單與按鈕SongDetail: 根據點擊的按鈕顯示的歌曲詳細資料
除此之外,我們還要安裝 react-redux 和 redux 套件來在我們的 React 專案中使用 Redux:
# Install package react-redux
$ npm install --save redux react-redux
# [Lecture] Design of the Redux App
在沒有使用 Redux 之前,我們的網頁應用程式組件架構與邏輯如下:
App組件:有List of Songs方法來呼叫SongList組件渲染在頁面上;有Selected song屬性可以傳遞給SongDetail組件SongList組件:必須監聽onSongSelect並將使用者選定的歌曲傳遞給App組件再傳遞給SongDetail組件SongDetail組件:根據App組件傳遞來的資訊渲染指定歌曲詳細資料
在使用 Redux 後,將由 Redux 管理所有狀態,其中:
Reducers- Song list reducers
- Selected song reducers
Action Creators- Select Song
# [Lecture] How React-Redux Works
# [Lecture] Redux Project Structure
一個較為清楚的 React Redux 專案目錄建議設置如下:
.
├── src/
│ ├── actions/ // Contains files related to action creators
│ ├── components/ // Files related to components
│ ├── reducers/ // Files related to reducers
│ └── index.js // Sets up both the react and redux sides of the app
├── ...
└── ...
接著在 /src/actions 文件夾下創建相關的文件,比如 index.js。這邊有個小技巧是當名稱取名相同時,在最外層的 index.js 檔案中要進行導入時,可以寫得較簡便:
// import actions from '../actions/index';
import actions from '../actions';
# [Lecture] Named vs Default Exports
創建 /src/actions/index.js:
// Action creator
export const selectSong = song => {
// Return an action
return {
type: "SONG_SELECTED",
payload: song
};
};
# [Lecture] Building Reducers
創建 /src/reducers/index.js:
const songsReducer = () => {
return [
{ title: "No Scrubs", duration: "4:05" },
{ title: "Macarena", duration: "2:30" },
{ title: "All Star", duration: "3:15" },
{ title: "Jump", duration: "1:15" }
];
};
const selectedSongReducer = (selectedSong = null, action) => {
if ((action.type = "SONG_SELECTED")) {
return action.payload;
}
return selectSong;
};
# [Lecture] Wiring Up the Provider
修改 /src/index.js:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import App from "./components/App";
import reducers from "./reducers";
ReactDOM.render(
<Provider store={createStore(reducers)}>
<App />
</Provider>,
document.querySelector("#root")
);
# [Lecture] The Connect Function
import React, { Component } from "react";
import { connect } from "react-redux";
class SongList extends Component {
render() {
return <div>SongList</div>;
}
}
export default connect()(SongList);
# [Lecture] Configuring Connect with MapStateToProps
import React, { Component } from "react";
import { connect } from "react-redux";
class SongList extends Component {
renderList() {
return this.props.songs.map(song => {
return (
<div className="item" key={song.title}>
<div className="right floated content">
<button className="ui button primary">Select</button>
</div>
<div className="content">{song.title}</div>
</div>
);
});
}
render() {
// this.props === { songs:state.songs }
return (
<div className="ui divided list">
{this.UNSAFE_componentWillMount.renderList}
</div>
);
}
}
const mapStateProps = state => {
return { songs: state.songs };
};
export default connect(mapStateProps)(SongList);