目录
(1)Redux的基本使用
- 安装redux依赖 npm i redux
- 新建store.js文件
store.js
// 1.引入redux
import { combineReducers, createStore } from 'redux'
// 2.创建reducer createStore( reducer )
const reducer = (prevState,action)=>{
let newState = {...prevState}
switch(action.type){
case 'change-city':
newState.city = action.data
break
}
return newState
}
//第一个参数 处理函数,第二个参数 起始值
const store = createStore(reducer,{city:''});
export default store
ShowCity.jsx
import React,{ useState } from 'react'
import store from '../redux/store'
export default function ChangeCity() {
let [city,setCity] = useState('')
// 订阅者,一旦数据改变就会被触发执行
store.subscribe(()=>{
setCity(()=>{
return store.getState().CityReducer.city
})
})
return (
<div>
<input type="text" defaultValue={city} />
</div>
)
}
Tianjin.jsx
import React from 'react'
import store from '../redux/store'
export default function Tianjin() {
function ChangeCity(){
// 发布者,执行store.dispatch会让订阅者收到消息
store.dispatch({
type:'change-city',
data:'天津'
})
}
return (
<div>天津<button onClick={ ()=>{ ChangeCity() } }>切换天津</button></div>
)
}
(2)redux的简单原理
function createStore(reducer,obj){
// state是用来存储状态的对象
let state = reducer(undefined,obj)
// list 用来存储消息队列
let list = []
// 订阅者,调用这个函数会将函数加入到消息队列中
function subscribe(callback){
list.push(callback)
}
// 发布者,调用这个函数会执行消息队列中的函数
function dispatch(action){
state = reducer(state,action)
for(let i=0;i<list.length;i++){
list[i]&&list[i]()
}
}
// 获得数据state
function getState(){
return state
}
return {
subscribe,
dispatch,
getState
}
}
(3)reducer合并
当开发中reducer都放现在一个文件时,多人开发代码会冲突,所以我们可以有多个reducer然后合并。
CityReducer.js 创建一个reducer
const reducer = (prevState,action)=>{
let newState = {...prevState}
switch(action.type){
case 'change-city':
newState.city = action.data
break
}
return newState
}
export default reducer
store.js
// 1.引入redux
import { combineReducers, createStore } from 'redux'
import CityReducer from './reducers/CityReducer'
// 2. 合并 reducer
const reducer = combineReducers({
CityReducer
})
//当合并reducer的时候,默认值对象就要分层级了,第一层的名字取决于合并时的名字
const store = createStore(reducer,{CityReducer:{city:''}});
export default store
ShowCity.jsx
import React,{ useState } from 'react'
import store from '../redux/store'
export default function ChangeCity() {
let [city,setCity] = useState('')
store.subscribe(()=>{
setCity(()=>{
// 取值时,也多了一层
return store.getState().CityReducer.city
})
})
return (
<div>
<input type="text" defaultValue={city} />
</div>
)
}
Tianjin.jsx
import React from 'react'
import store from '../redux/store'
export default function Tianjin() {
function ChangeCity(){
store.dispatch({
type:'change-city',
data:'天津'
})
}
return (
<div>天津<button onClick={ ()=>{ ChangeCity() } }>切换天津</button></div>
)
}
(4)redux-thunk
当有异步任务的时候,我们需要异步去更改store的状态,这时我们可以使用redux-thunk
store.js
import { applyMiddleware, createStore } from 'redux'
import reduxThunk from 'redux-thunk' // 引入 redux-thunk
const reducer = (piveStore,action)=>{
const newStore = {...piveStore}
switch(action.type){
case 'change-city':
newStore.city = action.data
break
}
return newStore
}
// applyMiddleware(reduxThunk)使用插件
const store = createStore(reducer,applyMiddleware(reduxThunk))
export default store
Tianjin.jsx
import store from '../store/index'
export default function(){
function cahngeCity(){
// redux-thunk配置好之后,dispatch可以传递一个函数了
// 这个函数接收一个dispatch函数,调用dispatch的时候就可以更新状态了
store.dispatch((dispatch)=>{
setTimeout(()=>{
dispatch({
type:'change-city',
data:'天津'
})
},3000)
})
}
return <div>
天津<button onClick={ ()=>{ cahngeCity() } }>切换天津</button>
</div>
}
Showcity.jsx
import store from '../store/index'
import { useState } from 'react'
export default function(){
const [city,changeCity] = useState()
// 正常的订阅内容
store.subscribe(()=>{
changeCity(store.getState().city)
})
return <div>
<input type="text" defaultValue={ city }/>
</div>
}
(5)redux-promise
和 redux-thunk一样,只不过传入的是一个promise对象
import store from '../store/index'
export default function(){
function cahngeCity(){
store.dispatch(new Promise((result,reject)=>{
setTimeout(()=>{
result()
},1000)
}).then(()=>{
return {
type:'change-city',
data:'天津'
}
}))
}
return <div>
天津<button onClick={ ()=>{ cahngeCity() } }>切换天津</button>
</div>
}
(6)取消订阅
注意:一定主要在组件函数中订阅,因为你取消订阅时,会导致组件重新渲染,重新调用组件函数,调用组件函数时又会订阅上消息,无限循环.....
import store from '../store/index'
import { useState } from 'react'
export default function(){
const [city,changeCity] = useState()
const [unsubscribe,changeUnsubscribe] = useState()
function subscribe(){
console.log('订阅')
// 订阅时,会返回一个唯一函数,调用这个函数就会取消订阅
const unsubscribeCall = store.subscribe(()=>{
changeCity(store.getState().city)
})
changeUnsubscribe({unsubscribe:unsubscribeCall})
}
function cancelSubscribe(){
unsubscribe.unsubscribe()
console.log('取消订阅')
}
return <div>
<input type="text" defaultValue={ city }/>
<button onClick={ ()=>{ subscribe() } }>订阅</button>
<button onClick={ ()=>{ cancelSubscribe() } }>取消订阅</button>
</div>
}
(7)redux devtools
GitHub - zalmoxisus/redux-devtools-extension: Redux DevTools extension.
import { createStore, compose,applyMiddleware} from 'redux'
import reducer from './reducer'
import reduxPromise from 'redux-promise'
reduxPromise
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// 想使用工具,需要用composeEnhancers包裹中间件,composeEnhancers函数从全局对象中获取或者从redux中获取
const store = createStore(reducer,composeEnhancers(applyMiddleware(reduxPromise)))
export default store
(8)react-redux
store.js
import { applyMiddleware, createStore } from 'redux'
import reduxPromise from 'redux-promise'
const reducer = (piveStore={
number:0
},action)=>{
const newStore = {...piveStore}
switch(action.type){
case 'change-number':
newStore.number++
}
return newStore
}
const store = createStore(reducer,applyMiddleware(reduxPromise))
export default store
index.js(重点)
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import store from './redux/store'
import App from './pages/App'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={ store }> // 使用Provider 传入 store
<App/>
</Provider>
);
App.jsx(重点)
import React, { Component } from 'react'
import { connect } from 'react-redux'
class App extends Component {
changeNumber(){
// 当使用了connect包裹组件之后,props会有一个dispatch去改变状态的值
this.props.dispatch({
type:'change-number',
})
}
render() {
return (
<div>
<h1>{this.props.number}</h1>
<button onClick={ ()=>{ this.changeNumber() } }>number++</button>
</div>
)
}
}
// 导出的组件使用 connect 包裹,传入一个函数,函数会接收一个值,这个值就是index.js导入进来的状态,并且return一个对象,return出去的这个对象会传到组件的props中
export default connect((state)=>{
console.log(state)
return {
msg:'hello world',
number:state.number+2
}
})(App)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。