持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
前言
之前三篇文章讲了react的hook(useState, useEffect, useContext)
文章地址:
下面再来看看另外一个常用的hook,useReducer。
Redux
在讲useReducer之前,我们要先讲讲Redux。因为它们是有关联的。我们可以把部分Redux的逻辑迁移到useReducer。
因为它们是相似的。
一般我们redux和react-redux结合使用。
"redux": "^4.2.0",
"react-redux": "^8.0.2"
要使用redux,要配置3个模块
actionsreducersstore
actions
这个是用来响应jsx的用户操作事件,然后把对应的数据传给reducer。
定义一个updateFn函数,接受text,返回一个对象, 里面是传入的text和type为UPDATE。
// actions/test.js
export function updateFn (text) {
return {
type: 'UPDATE',
text
}
}
reducers
reducer会对action传入的值做判断,然后返回数据。它接受2个参数,一个是prevState,也就是上一次reducer返回的值。第二个是就是action传入的值。
返回的数据会通过store传入到对应组件中,实现数据互通。
// reducer/test.js
function testReducer (prevState, action) {
if (action.type === 'UPDATE') {
return {
type: 'UPDATE',
text: action.text
}
}
return {
type: 'INITIAL',
text: 'hello world'
}
}
export default testReducer
store
store就是把reducer整合起来,供组件可以使用数据。通过createStore创建store。
// store/index.js
import { createStore, combineReducers } from 'redux'
import testReducer from '../reducers/test'
const allReducers = combineReducers({
test: testReducer
})
const store = createStore(allReducers)
export default store
然后再组件中注册store,这样才能在组件使用store。
代码如下
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import store from './store'
const root = createRoot(document.getElementById('root'))
root.render(
<Provider store={store}>
< App />
</Provider >
)
Provider标签包括,并传入store。这样App下的组件都能使用store了。
App组件使用例子:
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { updateFn } from '../actions/test'
class App extends PureComponent {
static propTypes = {
updateFn: PropTypes.func,
text: PropTypes.string
}
clickFn = () => {
this.props.updateFn('答案cp3')
}
render () {
const { text } = this.props
return (
<button className='test' onClick={this.clickFn}>
{text}
</button>
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
text: state.test.text
}
}
const mapDispatchToProps = (dispatch) => {
return {
updateFn: (text) => dispatch(updateFn(text))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
要使用mapStateToProps和mapDispatchToProps,一个是定义数据的,一个是定义dispatch方法。最后用connect方法调用即可,并传入组件。
在组件中使用this.props.xxx来访问,然后你点击按钮的时候,text从hello world就变成了答案cp3。
以上这一套流程下来,对新手还是复杂,最好是手动敲一遍。 下面来讲讲useReducer。
useReducer
如果使用了hook的useReducer,则上面很多代码都可以精简了,只需要actions和 reducer。
import React, { useReducer } from 'react'
import { updateFn } from '../actions/test'
import testReducer from '../reducers/test'
function App () {
const [state, dispatch] = useReducer(testReducer, 'hello world', (arg) => { return { text: arg } })
return (
<div onClick={() => dispatch(updateFn('答案cp3'))}>{state.text}</div>
)
}
export default App
div一开始内容是hello world,点击后就变成答案cp3,这样写是不是相对精简一点?
useReducer支持传3个参数,第一个是reducers,第二个是初始值,第三个是如果要对初始值做处理,可以在第三个参数提供函数,会把第二的初始值传入,返回的值就当作初始值。
useReducer返回的是数组,解构后第一个是state,第二个是dispatch。调用dispatch,传入actions的方法,就会更新state。
在某些场景下,可以使用useReducer,不需要redux。