学习下react的hook(useReducer)

126 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

前言

之前三篇文章讲了react的hook(useState, useEffect, useContext

文章地址:

下面再来看看另外一个常用的hook,useReducer

Redux

在讲useReducer之前,我们要先讲讲Redux。因为它们是有关联的。我们可以把部分Redux的逻辑迁移到useReducer

因为它们是相似的。

一般我们reduxreact-redux结合使用。

   "redux": "^4.2.0",
   "react-redux": "^8.0.2"   

要使用redux,要配置3个模块

  • actions
  • reducers
  • store

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)

要使用mapStateToPropsmapDispatchToProps,一个是定义数据的,一个是定义dispatch方法。最后用connect方法调用即可,并传入组件。

在组件中使用this.props.xxx来访问,然后你点击按钮的时候,text从hello world就变成了答案cp3

以上这一套流程下来,对新手还是复杂,最好是手动敲一遍。 下面来讲讲useReducer。

useReducer

如果使用了hook的useReducer,则上面很多代码都可以精简了,只需要actionsreducer

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。