react+redux实战——redux到底是个啥子?

本文是作者学习redux的分享,通过实战项目解释redux的基本概念,如store、action、reducer和combineReducers。文章介绍了如何在react应用中使用redux进行数据管理,并提供了项目代码和学习资源链接。
摘要由CSDN通过智能技术生成

写在前面

文章是个人初学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改变导致页面进行重新渲染

建议:个人是初学者,很多地方描述不太准确。大家可以先看一下学习视频和阮一峰老师的博客,然后可以看一下我的文章,有什么不准确的地方可以留言说明。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值