第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)
第十章:React相关扩展二(Fragment、Content、组件优化、render props、错误边界)(十)
第十一章:Redux相关知识(什么是redux、redux的工作原理、redux的核心概念、redux的基本使用)(十一)
第十二章:React-Redux相关知识(什么是react-redux、react-redux的原理、react-redux相关API、react-redux的基本使用)(十二)
如果还不会redux建议看完第十一章后再来看这章,这样会更好理解
Ract-Redux
是Redux的官方React绑定库
,它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。用redux 库来创建 store , 利用 react-redux 库来获取 store 中的数据或者更新数据。
- react-redux提供了两个常用的 api ,一个是:
Provider
,一个是:connect
。组件之间共享的数据是Provider这个顶层组件通过props传递下去的,store必须作为参数放到Provider组件中去。而connect则提供了组件获取 store中数据或者更新数据的接口。- 学习网站: https://react-redux.js.org/
React-Redux 将所有组件分成两大类: UI 组件
(负责 UI 的呈现)和容器组件
(负责管理数据和逻辑)。
UI组件
只负责 UI 的呈现,不带有任何业务逻辑
数据都由参数(this.props)提供
不使用任何 Redux 的 API
容器组件
负责管理数据和业务逻辑,不负责 UI 的呈现
使用 Redux 的 API
UI 组件和容器组件的结合
外面是一个容器组件
,里面包了一个UI组件
。前者负责与外部的通信
,将数据传给后者,由后者渲染出视图
。react-redux在7.1版本之前使用connect函数配合Provider来进行操作。以下介绍7.1版本之前的Provider及connect函数。
组件概念:connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。
React-Redux 提供Provider组件,可以让容器组件拿到state。
用法:在根组件外面包了一层Provider,App的所有子组件都可以拿到state了
。它的原理是React组件的context属性,store放在了上下文对象context上面。React-Redux自动生成的容器组件的代码,就类似下面这样,然后子组件就可以从context拿到store。
示例代码
import store from './redux/store'
// src/index.js
<Provider store={store}>
<App />
</Provider>
React-Redux中的connect()方法用于从 UI 组件生成容器组件
,connect(mapStateToProps?,
mapDispatchToProps?, mergeProps?, options?) 。之后就可以在该组件的props中获取到仓库中数据和dispatch方法。
export default connect(mapStateToProps, mapDispatchToProps)(ConponentUI);
mapStateToProps
字面含义是把state映射到props中去
,意思就是把Redux中的数据映射到React中的props中去。
建立一个从外部state对象到 UI 组件的props对象的映射关系
。执行后返回一个对象,
里面的每一个键值对就是一个映射。当state更新的时候,就会自动执行
,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。// 映射仓库中的数据到props中
const mapStateToProps = (state, ownProps) => {
return {
inputValue: state.inputValue,
test: 'hello',
listData: state.listData
}
}
mapStateToProps 字面含义是把dispatch映射到props中去,意思就是把Redux中的修改数据的方法映射到React中的props中去。
// 映射仓库中的dispatch到props中
const mapDispatchToProps = (dispatch, ownProps) => {
return {
inputChange: (e) => {
// 获取input数据,更改store中的数据
let action = {
type: 'TO_CHANGE_INPUT',
value: e.target.value
};
// 分发action
dispatch(action);
},
// 添加
toAdd: () => {
let action = {
type: 'TO_ADD'
};
dispatch(action);
},
// 删除
toDelete: (index) => {
// console.log(index);
let action = {
type: 'TO_DELETE',
index
};
dispatch(action);
},
// 完成
toChangeStatus: (index) => {
let action = {
type: 'TO_CHANGE_STATUS',
index
};
dispatch(action);
},
}
}
安装
npm install react-redux --save
# 或
yarn add react-redux
代码案例片段:
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
App.js
import React, { Component } from 'react'
import Count from './containers/Count' //引入的Count的容器组件
import Person from './containers/Person' //引入的Person的容器组件
export default class App extends Component {
render() {
return (
<div>
<Count/>
<hr/>
<Person/>
</div>
)
}
}
redux/action/count.js(该文件专门为Count组件生成action对象)
//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:'increment',data})
export const createDecrementAction = data => ({type:'decrement',data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}
redux/action/person.js(该文件专门为Person组件生成action对象)
//创建增加一个人的action动作对象
export const addPerson = personObj => ({type:'add_person',data:personObj})
redux/reducer/count.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
const initState = {
value:0,index:1
}
//初始化状态
export default function countReducer (preState = initState, action) {
console.log('preState:',preState);
console.log('action:',action);
//从action对象中获取:type、data
const { type, data } = action
//根据type决定如何加工数据
switch (type) {
case 'increment': //如果是加
return {
...preState,
value: preState.value + data
}
case 'decrement': //若果是减
return {
...preState,
value: preState.value - data
}
default:
return preState
}
}
redux/reducer/person.js
//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]
export default function personReducer(preState=initState,action){
// console.log('personReducer@#@#@#');
const {type,data} = action
switch (type) {
case 'add_person': //若是添加一个人
//preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
return [data,...preState]
default:
return preState
}
}
redux/reducer/index.js
/*
该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
//引入为Person组件服务的reducer
import persons from './person'
//汇总所有的reducer变为一个总的reducer
export default combineReducers({
count,
persons
})
redux/store.js
/*
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
// 旧版
// import { createStore } from 'redux'
//新版
import { legacy_createStore as createStore, applyMiddleware } from 'redux'
//引入汇总之后的reducer
import reducer from './reducers'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//引入redux-devtools-extension
import {composeWithDevTools} from 'redux-devtools-extension'
//暴露store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
container/Count.jsx
import React, { Component } from "react";
//引入action
import {
increment,
decrement,
incrementAsync,
} from "../../redux/actions/count";
//引入connect用于连接UI组件与redux
import { connect } from "react-redux";
//定义UI组件
class Count extends Component {
state = { carName: "奔驰c63" };
//加法
increment = () => {
const { value } = this.selectNumber;
this.props.increment(value * 1);
};
//减法
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value * 1);
};
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.increment(value * 1);
}
};
//异步加
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value * 1, 500);
};
render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
<h4>当前求和为:{this.props.count}</h4>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
//使用connect()()创建并暴露一个Count的容器组件
//写法一
/*
//1.mapStateToProps函数返回的是一个对象;
//2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
//3.mapStateToProps用于传递状态
function mapStateToProps(state){
return {count:state.count.value}
}
//1.mapDispatchToProps函数返回的是一个对象;
//2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
//3.mapDispatchToProps用于传递操作状态的方法
function mapDispatchToProps(dispatch){
return {
jia:number => dispatch(createIncrementAction(number)),
jian:number => dispatch(createDecrementAction(number)),
jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps,mapDispatchToProps)(Count)
*/
//写法二
/*
export default connect(
state => ({count:state.count.value}),
//mapDispatchToProps的一般写法
//dispatch => ({
// jia:number => dispatch(createIncrementAction(number)),
// jian:number => dispatch(createDecrementAction(number)),
// jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
// })
//mapDispatchToProps的简写
{
jia:createIncrementAction,
jian:createDecrementAction,
jiaAsync:createIncrementAsyncAction,
}
)(Count)
*/
//写法三(推荐)
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
(state) => ({
count: state.count.value,
personCount: state.persons.length,
}),
{ increment, decrement, incrementAsync }
)(Count);
container/Person.jsx
import React, { Component } from 'react'
import {nanoid} from 'nanoid'
import {connect} from 'react-redux'
import {addPerson} from '../../redux/actions/person'
class Person extends Component {
addPerson = ()=>{
const name = this.nameNode.value
const age = this.ageNode.value*1
const personObj = {id:nanoid(),name,age}
this.props.addPerson(personObj)
this.nameNode.value = ''
this.ageNode.value = ''
}
render() {
return (
<div>
<h2>我是Person组件,上方组件求和为{this.props.count}</h2>
<input ref={c=>this.nameNode = c} type="text" placeholder="输入名字"/>
<input ref={c=>this.ageNode = c} type="text" placeholder="输入年龄"/>
<button onClick={this.addPerson}>添加</button>
<ul>
{
this.props.persons.map((p)=>{
return <li key={p.id}>{p.name}--{p.age}</li>
})
}
</ul>
</div>
)
}
}
export default connect(
state => ({
persons:state.persons,
count:state.count.value
}),//映射状态
{addPerson}//映射操作状态的方法
)(Person)