React 和 Redux 是两个独立的库,两者之间职责独立,因此,为了更好的实现在 React 中使用 Redux 进行状态管理,就需要一种机制,将这两个独立的库关联在一起,这就是 react-redux 出现的原因
1.基本使用
yarn add react-redux或者npm i react-redux
2.配置index.js
import ReactDOM from 'react-dom'
import App from './App.js'
import store from './store/store.js'
import { Provider } from 'react-redux'
// 通过 Provider 提供 store 供其他组件内部使用
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#root')
)
3.react-redux 提供了 useSelector 和 useDispatch
App.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './store/actions'
const App = () => {
const count = useSelector((state) => state)
const dispatch = useDispatch()
return (
<div>
<h3>{count}</h3>
<div>
<button onClick={() => dispatch(increment(1))}>+1</button>
<button onClick={() => dispatch(increment(5))}>+5</button>
<button onClick={() => dispatch(decrement(1))}>-1</button>
<button onClick={() => dispatch(decrement(5))}>-5</button>
</div>
</div>
)
}
export default App
如果其他 组件想用,看看有多方便吧,无需传值,直接拽过来!
import React from 'react'
import { useSelector } from 'react-redux'
export default function Test() {
const money = useSelector((state) => state)
return <div>{money}</div>
}
Reducer 的分离与合并
-
问题:此时项目中会有多个 reducer,但是 store 只能接收一个 reducer,因此需要将多个 reducer 合并为一个 reducer,才能传递给 store 使用。
-
解决:使用 Redux 中的
combineReducers({ counter: counterReducer, user: userReducer })
函数。 -
注意:组件中再想只使用 counter 的状态,需要
const count = useSelector((state) => state.counter)
-
每个 reducer 应该只关注自己的数据,例如:
a,登录功能:
loginReducer
处理的只应该是跟登录相关的状态。b,个人资料:
profileReducer
处理的只应该是跟个人资料相关的状态。c,文章列表、文章详情、文章评论等。
步骤
-
reducers.js
中新建 userReducer。 -
通过 combineReducers 合并 counter 和 user 并导出。
-
修改
App.js
和Test.js
获取数据的方式。 -
新建
User.js
测试 userReducer 的使用
reducers.js
import { combineReducers } from 'redux'
function counter(state = 10, action) {
switch (action.type) {
case 'INCREMENT':
return state + action.payload
case 'DECREMENT':
return state - action.payload
default:
return state
}
}
function user(state = { name: 'ifer', age: 18 }, action) {
switch (action.type) {
case 'UPDATENAME':
return {
...state,
name: action.payload,
}
default:
return state
}
}
export default combineReducers({
counter,
user,
})
App.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './store/actions'
import Test from './Test'
import User from './User'
const App = () => {
const count = useSelector((state) => state.counter)
const dispatch = useDispatch()
return (
<div>
<h3>{count}</h3>
<div>
<button onClick={() => dispatch(increment(1))}>+1</button>
<button onClick={() => dispatch(increment(5))}>+5</button>
<button onClick={() => dispatch(decrement(1))}>-1</button>
<button onClick={() => dispatch(decrement(5))}>-5</button>
</div>
<Test />
<User />
</div>
)
}
export default App
Test.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment } from './store/actions'
export default function Test() {
const count = useSelector((state) => state.counter)
const dispatch = useDispatch()
return (
<div>
<p>Test {count}</p>
<div>
<button onClick={() => dispatch(increment(5))}>click</button>
</div>
</div>
)
}
use.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateName } from './store/actions'
export default function User() {
const user = useSelector((state) => state.user)
const dispatch = useDispatch()
const handleClick = () => {
dispatch(updateName('xxx'))
}
return (
<div>
<h3>{user.name}</h3>
<button onClick={handleClick}>update name</button>
</div>
)
}
actions.js
export const updateName = (payload) => ({
type: 'UPDATENAME',
payload,
})