文章是个人初学redux的分享,从redux基础知识点到使用redux搭建简单的表单提交项目。
项目代码地址:https://github.com/jishuaizhen/react-redux-simple-project.git
项目学习视频:https://ke.qq.com/course/368915
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发生变化之后,组件获取数据进行页面渲染。
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 (
添加内容
)
}
...
//绑定函数
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是为了状态(数据)的统一管理,为了让所有组件拿到状态,需要使用 将根组件包裹
import {Provider} from 'react-redux'
function App() {
return (
);
}
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改变导致页面进行重新渲染
建议:个人是初学者,很多地方描述不太准确。大家可以先看一下学习视频和阮一峰老师的博客,然后可以看一下我的文章,有什么不准确的地方可以留言说明。