寫在前面
文章是個人初學redux的分享,從redux基礎知識點到使用redux搭建簡單的表單送出項目。
項目代碼位址:https://github.com/jishuaizhen/react-redux-simple-project.git
項目學習視訊:https://ke.qq.com/course/368915
一、redux到底是個啥子?
1.redux和vuex具有類似的作用,為了友善元件間的資料通信而産生。
2.簡單了解:redux和vuex都提供了一個資料倉庫,元件無法直接修改倉庫中的資料,需要使用redux中提供的方法傳參修改或者擷取資料。
3.注意:redux涉及到三個比較重要的點:store、action、reducer;另外,在使用redux的時候參數也是傳來傳去的,比較麻煩,容易繞暈。
4.redux的詳細介紹:阮一峰老師的部落格http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
5.
在圖中可以看到,使用redux之後:1.使用者觸發元件中的事件,需要送出或者擷取資料;2.action接到使用者的操作并派發;3.action在派發過程會經過store,攜帶store中的資料和action(具體操作)提供給reducer;4.reducer處理之後傳回最新的狀态(也就是資料),更新store中的資料;5.當store發生變化之後,元件擷取資料進行頁面渲染。
二、react+redux實戰
1.這裡是我學習練習的一個小案例,架構使用create-react-app,請求的接口使用http://jsonplaceholder.typicode.com/posts
2.頁面布局
頁面上方是添加标題和内容的文本框,頁面下方是請求接口的資料
3.主檔案App.js
元件檔案在components檔案夾中,actions負責操作分發,reducers負責資料的處理,store.js負責
三、分步操作
1.Posts.js元件
fetch('http://jsonplaceholder.typicode.com/posts')
.then(res=>res.json())
.then(posts=>{
this.setState({
posts:posts
})
})
//通過請求擷取資料渲染到頁面
2.PostsForm.js元件
//渲染功能
render() {
return (
<div>
<h1>添加内容</h1>
<form onSubmit={this.onSubmit}>
<div>
<label>title</label>
<br/>
<input type="text" name="title" onChange={this.onChange} value={this.state.title}></input>
</div>
<div>
<label>body</label>
<br/>
<textarea name="body" onChange={this.onChange} value={this.state.body}></textarea>
</div>
<br/>
<button type="submit">添加</button>
</form>
</div>
)
}
...
//綁定函數
onChange=(e)=>{
console.log(e.target)
this.setState({
[e.target.name]:e.target.value
})
}
onSubmit=(e)=>{
e.preventDefault()
const post = {
title:this.state.title,
body:this.state.body
}
}
//資料請求
fetch('http://jsonplaceholder.typicode.com/posts',{
method:'POST',
header:{
"content-type":"application/json"
},
body:JSON.stringify(postData)
})
.then(res=>res.json())
.then(data=>{console.log(data)}
)
3.初識store
1.npm i redux react-redux redux-thunk
2.使用redux是為了狀态(資料)的統一管理,為了讓所有元件拿到狀态,需要使用<Provider></Provider>将根元件包裹
import {Provider} from 'react-redux'
function App() {
return (
<Provider store={store}>
<div className="App">
<PostForm></PostForm>
<Posts></Posts>
</div>
</Provider>
);
}
3.建立store, Redux 應用隻有一個單一的 store。當需要拆分資料處理邏輯時,你應該使用 reducer 組合而不是建立多個 store
import {createStore,applyMiddleware,compose} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/index'
const initialState = {}
const middleware = [thunk]
//createStore可以傳三個參數:1.多個reducer對象;2.初始狀态為空對象,當調用redux之後會傳回一個新的對象;3.中間件applyMiddlewares是 Redux 的原生方法,作用是将所有中間件組成一個數組,依次執行
export const store = createStore(
rootReducer,
initialState,
applyMiddleware(...middleware)
)
4.Reducer和CombineReducers
1.Reducer
Store 收到 Action 以後,必須給出一個新的 State,這樣 View 才會發生變化。這種 State 的計算過程就叫做 Reducer。Reducer 是一個函數,它接受 Action 和目前 State 作為參數,傳回一個新的 State。
export default function(state=initialState,action){
switch(action.type){
default:
return state;
}
}
2.Reducer 的拆分
Reducer 函數負責生成 State。由于整個應用隻有一個 State 對象,包含所有資料,對于大型應用來說,這個 State 必然十分龐大,導緻 Reducer 函數也十分龐大,是以需要拆分Reducer。
//在創造store過程中rootReducer是多個對象
export const store = createStore(
rootReducer,
initialState,
applyMiddleware(...middleware)
)
3.CombineReducers
這樣一拆,Reducer 就易讀易寫多了。而且,這種拆分與 React 應用的結構相吻合:一個 React 根元件由很多子元件構成。這就是說,子元件與子 Reducer 完全可以對應。
Redux 提供了一個combineReducers方法,用于 Reducer 的拆分。你隻要定義各個子 Reducer 函數,然後用這個方法,将它們合成一個大的 Reducer。
import {combineReducers} from 'redux'
import postReducer from './postReducer'
export default combineReducers({
posts:postReducer
})
5.actions和types
1.我們需要在actions檔案夾裡面定義操作的函數,然後在元件内進行調用。
重點:這一步就是将原本存在在元件中的操作(資料請求等)轉移到actions中。元件調用actions中的方法就需要使用connect建立連結,React-Redux 提供connect方法,用于從 UI 元件生成容器元件。connect的意思,就是将這兩種元件連起來。
import { connect } from 'react-redux'
import { fetchPosts } from '../actions/postActions'
const mapStateToProps = state => ({
posts:state.posts.items,
newPost:state.posts.item
})
export default connect(mapStateToProps,{fetchPosts})(Posts);
2.現在我們可以通過元件調用actions裡面的方法
重點:redux需要actions的dispatch分發操作攜帶方法和store中的狀态交給reducer進行處理,reducer傳回更新後的狀态(資料),元件進行更新。actions中有多種操作,是以在dispatch分發操作時需要配置action的types屬性進行分辨執行哪個操作。
//建立types.js檔案,types檔案就是為不同action定義不同名字,需要在actions和reducers檔案中引入,以便讓reducer知道解決哪一種操作
export const FETCH_POSTS = "FETCH_POSTS";
export const NEW_POSTS = "NEW_POSTS";
3.
//postActions.js檔案
export const fetchPosts = () => dispatch => {
fetch('http://jsonplaceholder.typicode.com/posts')
.then(res=>res.json())
.then(posts=>
// 當操作成功時,通過dispatch攜帶action.type和請求到資料給store,store告訴postReducer.js進行操作,傳回處理後的狀态
dispatch({
type:FETCH_POSTS,
payload:posts
})
)
}
//postReducer.js
export default function(state=initialState,action){
switch(action.type){
case NEW_POSTS:
return {
...state,
item:action.payload
}
case FETCH_POSTS:
return {
...state,
items:action.payload
}
default:
return state;
}
}
6.mapState擷取最新狀态
1.postReducer.js接收到action.type和請求到資料進行處理傳回新的狀态,這裡reducer處理action操作得到的資料進行處理傳回新的資料給store。
2.store中的資料更新,元件需要想辦法進行接收。
mapStateToProps()是一個函數。它的作用就是像它的名字那樣,建立一個從(外部的)state對象到(UI 元件的)props對象的映射關系。
const mapStateToProps = state => ({
posts:state.posts.items
})
export default connect(mapStateToProps,{fetchPosts})(Posts);
3.另外redux要求我們需要給方法和狀态規定資料類型
import PropTypes from 'prop-types'
//使用方法
Posts.proptypes = {
fetchPosts:PropTypes.func.isRequired,
posts:PropTypes.array.isRequired
}
7.添加資料
1.接收到文本框的資料PostForm.js
onSubmit=(e)=>{
e.preventDefault()
const post = {
title:this.state.title,
body:this.state.body
}
// 觸發action
this.props.createPost(post)
}
2.PostActions.js接收到操作通知
export const createPost = postData => dispatch => {
fetch('http://jsonplaceholder.typicode.com/posts',{
method:'POST',
header:{
"content-type":"application/json"
},
body:JSON.stringify(postData)
})
.then(res=>res.json())
.then(post=>
// 當操作成功時,通過dispatch将資料和action.type交給postReducer.js處理
dispatch({
type:NEW_POSTS,
payload:post
})
)
}
3.postReducer.js根據對應的操作傳回處理後的資料
export default function(state=initialState,action){
switch(action.type){
case NEW_POSTS:
return {
...state,
item:action.payload
}
case FETCH_POSTS:
return {
...state,
items:action.payload
}
default:
return state;
}
}
4.資料更改後,Post.js接收資料進行渲染
const mapStateToProps = state => ({
posts:state.posts.items,
newPost:state.posts.item //這裡是添加的資料
})
寫在最後
1.自認為redux比vuex複雜些,操作和資料類型要求的更規範些
2.官方将store中的資料定義為狀态,狀态改變即為資料更新,是以文章中有些地方使用狀态和資料兩種說明
3.使用redux後操作和資料請求不在元件中進行,而是交給actions和reducers,reducers将資料處理後傳回給store,store通過mapStateToProps()方法将store中的資料對象和UI元件中的props進行映射,props改變導緻頁面進行重新渲染
建議:個人是初學者,很多地方描述不太準确。大家可以先看一下學習視訊和阮一峰老師的部落格,然後可以看一下我的文章,有什麼不準确的地方可以留言說明。