Redux - 用 Redux Thunk 避免重複請求
=================== 準備 ========================
- 每當我們 dispatch 一個 function,Redux 會接住它並直接呼叫
export const fetchPostsAndUsers = () => async dispatch => {
await // 需要 await 因為呼叫的是 async function,我們要等它完成
dispatch( // dispatch 一個 "async dispatch..." function,所以會直接呼叫它
dispatch( // dispatch 一個 "async dispatch..." function,所以會直接呼叫它
fetchPosts() // 呼叫 export const fetchPosts = ()
// 然後回傳 "async dispatch => { ... }"
// 然後回傳 "async dispatch => { ... }"
)
}
export const fetchPosts = () => async dispatch => {
const response = await jsonPlaceholder.get('/posts')
dispatch({type:'FETCH_POSTS', payload: response.data})
}
- Redux Thunk 會呼叫 action creator 的 function 參數:dispatch 和 getState
Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
- Lodash 的 _.map function 可以根據條件來 map 集合(https://lodash.com/docs/3.10.1#map)
If a property name is provided for iteratee the created _.property style callback returns the property value of the given element.
- Lodash 的 _.uniq function 可以建立不重複的陣列(https://lodash.com/docs/#uniq)
Creates a duplicate-free version of an array, using SameValueZero for equality comparisons, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.
===================== 需要修改的部分 =================
- 移除 memoize function
export const fetchUser = (userId) => async dispatch => {
const response = await jsonPlaceholder.get(`/users/${userId}`)
dispatch({type:'FETCH_USER', payload: response.data})
}
- 建立 fetchPostsAndUsers function
export const fetchPostsAndUsers = () => async (dispatch, getState) => {
await dispatch (fetchPosts());
const userIds = _.uniq(_.map(getState().fetchPosts, 'userId'))
userIds.forEach(id => dispatch(fetchUser(id)))
}
- 從 PttPosts.js 抓取文章和使用者
import React, {Component} from "react";
import {connect} from 'react-redux'
import {fetchPostsAndUsers, selectPttPost} from "../actions";
import UserHeader from "./UserHeader";
class PttPosts extends Component {
componentDidMount() {
this.props.fetchPostsAndUsers()
}
renderList() {
if (this.props.postList) {
return this.props.postList.map((post) => {
return <div key={post.id}>
<div key={post.id}><a onClick={() => this.props.selectPttPost(post)}>Title:{post.title}</a></div>
<UserHeader userId={post.userId} />
</div>
});
} else {
return 'Loading...'
}
};
render() {
return <div>{this.renderList()}</div>
}
}
const mapStateToProps = (state) => {
return {postList: state.fetchPosts};
}
export default connect(mapStateToProps, { fetchPostsAndUsers, selectPttPost })(PttPosts)
- UserHeader.js 不再需要自己 fetchUsers
import React, {Component} from "react";
import {connect} from 'react-redux'
class UserHeader extends Component {
render() {
return <div>Author: {this.props.user?.name}</div>
}
}
const mapStateToProps = (state, props) => {
return {user: state.users?.find(user => user.id === props.userId)}
}
export default connect(mapStateToProps, {fetchUser})(UserHeader)
- 重複的請求消失了
