随便写写之实现一个react-redux的简单demo
react-redux其实就是对redux进行基于react框架的进一步的封装,其底层核心还是使用的redux原理。结合如下流程图,我们先用react-redux来实现本文的小例子来看下react-redux 的具体使用,此文适合初学者。
Provider
react-redux 提供了一个Provider
组件,该组件可以将store提供给所有的子组件使用,其利用的是react的context属性实现,具体使用方法如下:
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包裹App,目的是让App所有的子容器组件都能接收到 store信息 */
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
// 在app容器组件中,通过引入两个子容器组件 Count、Person,并通过这两个组件之间的交互来实现本文的效果
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>
)
}
}
如上所示,我们在入口文件index.js引入Provider
和store
;然后利用Provider
将store
注入到所有的子组件中,这样所有的子组件就就可以拿到 store 了。该特性利用的是react的context属性,相当于将 store
数据共享给所有的子容器组件。
store
首先,在核心文件 store.js 中,通过redux提供的createStore
创建一个store实例,createStore
接收一个reducer
函数作为参数,第二个参数用来支持异步action。
// 引入createStore创建redux中最为核心的store对象; applyMiddleware用来支持异步action的中间件
import { createStore, applyMiddleware } from 'redux'
// 引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
// 引入redux-devtools-extension
import { composeWithDevTools } from 'redux-devtools-extension'
// 引入combineReducers,用于汇总多个reducer
import { combineReducers } from 'redux'
// 引入所有的 reducer
import count from './reducers/count'
import persons from './reducers/person'
// 引入所有的reducer变为一个总的reducers
const allReducer = combineReducers({
count,
persons
})
//暴露store
export default createStore( allReducer, composeWithDevTools(applyMiddleware(thunk)))
创建action和reducer
如下图是action
和 reducer
绑定后的数据交互图,可以很好的解释上图中的右边部分。在视图组件中通过dispatch
发起动作对象 action
, 同时reducer
函数会接到两个参数,分别为:之前的状态 preState ,动作对象action,在reducer
函数里面通过action对象中的type类型来执行对应的操作,得到最新的state 数据。流程如下图所示:
继续实现上述的demo的action:
// 该文件专门为Count组件生成action对象
export const increment = data => ({type: 'increment', data})
export const decrement = data => ({type: 'increment', data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const incrementAsync = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(increment(data))
},time)
}
}
// 该文件专门为Person组件生成action对象
export const addPerson = personObj => ({type: 'addPerson',data: personObj})
继续实现上述的demo的 reducer:
// 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
// 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
const initState = 0 //初始化状态
export default function countReducer(preState = initState, action){
//从action对象中获取:type、data
const { type, data } = action
switch (type) {
case 'increment': // 如果是加
return preState + data
case 'decrement': // 如果是减
return preState - data
default:
return preState
}
}
// 该文件是用于创建一个为 Person 组件服务的reducer
const initState = [{ id:'8', name:'kobe', age:24 }]
export default function personReducer(preState = initState, action){
const {type,data} = action
switch (type) {
case 'addPerson': //若是添加一个人
return [data,...preState]
default:
return preState
}
}
子容器组件的实现
// Count 组件的实现
import React, { Component } from 'react'
import { increment, decrement, incrementAsync } from '../../redux/actions/count'
import {connect} from 'react-redux'
//定义UI组件
class Count extends Component {
//加法
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() {
return (
<div>
{/* 此处可以取到其他组件的state数据 */}
<h2>我是Count组件,下方组件总人数为:{this.props.personCount</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的容器组件
export default connect(
state => ({
count: state.count,
personCount: state.persons.length
}),
{increment, decrement, incrementAsync}
)(Count)
// Person 组件的实现
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>
)
}
}
// 使用connect()()创建并暴露一个Person的容器组件
export default connect(
state => ({
persons:state.persons,
count:state.count
}),
{addPerson}
)(Person)
转载自:https://juejin.cn/post/7270829679087091772