零,对应的视频学习资料
https://www.bilibili.com/video/BV1w441137ss
项目地址:https://gitee.com/ling-xu/react-redux-demo
对应此视频的系列笔记:
1-15节redux:https://blog.csdn.net/weixin_42349568/article/details/117196231
16-17节-redux-chunk:https://blog.csdn.net/weixin_42349568/article/details/117248649
18-19节-redux-saga:https://blog.csdn.net/weixin_42349568/article/details/117251408
20-24节-react-redux:https://blog.csdn.net/weixin_42349568/article/details/117266913
一,redux解决了什么问题
在没有redux的时候,react的各个组件间的数据传递如左图所示,只能挨个进行,如果紫色组件需要修改其他组件的状态值,就需要一个个组件传递数据状态的变化。
而引入redux之后,就相当于在全局区域创建了一个专门用来管理状态值的仓库,通过紫色组件修改这个仓库对应的值,就可以完成依赖于这个值的其他组件的状态更新。(单向数据流,子修改store,依赖于store的会自动更新修改)
二,redux的工作流程
在react的组件中,不再使用自身的状态,而是通过action从store中去查找使用里面存放的状态,而这些状态的管理体系,就是这个reducers.
三,实际小demo
1,安装antd
npm install antd --save
2,新建todolist组件
import React from 'react'
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'
const data = ['早上八点,需需求沟通', '早上九点,吃零食', '早上10点,摸鱼开始']
class TodoList extends React.Component {
render() {
return (
<div>
<div style={{ margin: '10px', display: 'flex', justifyContent: 'space-between' }}>
<Input placeholder="添加待办事项" style={{ borderRadius: '5px' }} />
<Button type="primary" style={{ width: '60px', height: '40px', marginLeft: '10px', borderRadius: '6px' }}>
增加
</Button>
</div>
<div style={{ margin: '10px' }}>
<List
bordered
dataSource={data}
renderItem={item => <List.Item>{item}</List.Item>}>
</List>
</div>
</div>
)
}
}
export default TodoList
3,安装redux
npm install --save redux
4,创建一个仓库store
index.js:
import {createStore} from 'redux'
const store = createStore()
export default store
5,创建一个reducer,完成仓库中的数据内容管理
reducer.js
const defaultState = {
inputValue:'请添加待办事项',
list:['早上八点,需需求沟通', '早上九点,吃零食', '早上10点,摸鱼开始']
}
const reducer= (state = defaultState, action) => {
return state
}
export default reducer
然后再修改index.js
import {createStore} from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
然后再在页面组件上获取这个值完成渲染:
6,谷歌扩展程序安装Redux DevTools
然后在index.js修改:
import {createStore} from 'redux'
import reducer from './reducer'
const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
export default store
就可以使用啦:
7,修改store中地数据
使用的是store.dispatch方法,一旦调用这个函数,则会执行reducer方法,且形参action为传递进去的对象。
8,使用store.subscribe(this.storeChange)注册订阅
当我们通过store.dispatch方法修改更新了store中的数据内容,但是组件中并不会完成更新:
当我点击菜单,可以看到,store中的数据已经修改了,但是页面渲染的数据并没有发生变化,也就是并没有从store中获取到最新的数据。
这就需要注册监听数据变化:一旦store数据变化,就执行某个传入的回调函数,更新当前组件的state:
9,实现删除功能
10,把action的状态抽离出来形成action-type.js文件
这样就可以统一管理状态,降低了bug的出现概率。
11,把所有的action抽离出来形成独立的action文件
12,redux的一些坑
1,store必须是唯一的,只能有一个store空间。
2,只有store才能改变自己的内容(reducer返回新的state,传给createStore内部函数处理。),reducer不能改变(所以之前是深拷贝一份进行处理)
3,reducer必须是纯函数(同样的输入必须对应确定的唯一结果)
四,将ui和js实现分离
实际上是把ui部分抽离出来,形成一个独立的组件,然后其中的数据和方法,通过属性绑定的形式,props接收来实现。
ui组件:
import React from 'react'
import { Input, Button, List } from 'antd'
import 'antd/dist/antd.css'
class TodoListUI extends React.Component {
render() {
return (
<div>
<div style={{ margin: '10px', display: 'flex', justifyContent: 'space-between' }}>
<Input
placeholder={this.props.inputValue}
style={{ borderRadius: '5px' }}
onChange={this.props.inputChange}
value={this.props.inputValue}
/>
<Button type="primary" onClick={this.props.addItem} style={{ width: '60px', height: '40px', marginLeft: '10px', borderRadius: '6px' }}>
增加
</Button>
</div>
<div style={{ margin: '10px' }}>
<List
bordered
dataSource={this.props.list}
renderItem={(item, index) => <List.Item onClick={()=>{this.props.deleteItem(index)}}>{item}</List.Item>}
></List>
</div>
</div>
)
}
}
export default TodoListUI
导入使用ui组件:
import React from 'react'
import 'antd/dist/antd.css'
import store from './redux/index'
import {inputChangeActionn,deleteItemActionn,addItemActionn} from './redux/action'
import TodoListUI from './TodoListUI'
class TodoList extends React.Component {
constructor(props){
super(props)
this.state=store.getState()
this.storeChange=this.storeChange.bind(this)
store.subscribe(this.storeChange)
this.addItem=this.addItem.bind(this)
this.deleteItem=this.deleteItem.bind(this)
}
storeChange(){
this.setState(store.getState())
}
inputChange(e){
// console.log(e.target.value)
const action=inputChangeActionn(e.target.value)
store.dispatch(action)
}
deleteItem(index){
const action=deleteItemActionn(index)
store.dispatch(action)
}
addItem(){
const action=addItemActionn()
if(this.state.inputValue ===''){
console.log("kogn ")
return
}
store.dispatch(action)
}
render() {
return (
<TodoListUI
inputValue={this.state.inputValue}
list={this.state.list}
inputChange={this.inputChange}
addItem={this.addItem}
deleteItem={this.deleteItem}
></TodoListUI>
)
}
}
export default TodoList
五,组件更改为无状态的组件(函数式组件)
注意到现在的组件,是从store中获取状态值,所以说他可以变更为无状态组件的写法:
import React from 'react'
import { Input, Button, List } from 'antd'
import 'antd/dist/antd.css'
const TodoListUI=(props)=>{
return (
<div>
<div style={{ margin: '10px', display: 'flex', justifyContent: 'space-between' }}>
<Input
placeholder={props.inputValue}
style={{ borderRadius: '5px' }}
onChange={props.inputChange}
value={props.inputValue}
/>
<Button type="primary" onClick={props.addItem} style={{ width: '60px', height: '40px', marginLeft: '10px', borderRadius: '6px' }}>
增加
</Button>
</div>
<div style={{ margin: '10px' }}>
<List
bordered
dataSource={props.list}
renderItem={(item, index) => <List.Item onClick={()=>{props.deleteItem(index)}}>{item}</List.Item>}
></List>
</div>
</div>
)
}
export default TodoListUI
六,fastmock新建接口,从axios初始化数据
componentDidMount(){
axios.get('https://www.fastmock.site/mock/88bbb3bb8d6ea3dc8f09431a61ce2e50/mymock_test/api/list')
.then((res)=>{
console.log(res)
const action=getList(res)
store.dispatch(action)
})
}
从axios初始化数据
componentDidMount(){
axios.get('https://www.fastmock.site/mock/88bbb3bb8d6ea3dc8f09431a61ce2e50/mymock_test/api/list')
.then((res)=>{
console.log(res)
const action=getList(res)
store.dispatch(action)
})
}