如何将带回调的类组件setState逻辑转换为React useState hook实现
类组件setState回调转函数式组件的实现方案
类组件中setState的第二个参数为状态更新完成后的同步回调,函数式组件的useState更新没有原生的回调参数,可通过以下两种方案实现等价逻辑:
方案1:useEffect监听实现(匹配原有写法逻辑)
核心思路是监听需要回调触发的状态messageToSend,状态更新后自动执行目标方法sendMsgAxios。
第一步:声明相关状态
import { useState, useEffect } from 'react' import axios from 'axios' // 函数组件内部声明状态 const [btnSendMeIsDisabled, setBtnSendMeIsDisabled] = useState(false) const [btnSendIsDisabled, setBtnSendIsDisabled] = useState(false) const [messageToSend, setMessageToSend] = useState([]) const [messages, setMessages] = useState([]) const [counter, setCounter] = useState(0) // 原有sendMsgAxios方法实现,使用messageToSend状态 const sendMsgAxios = () => { // 原有逻辑不变,直接读取messageToSend状态即可 }
第二步:添加useEffect监听
// 仅当messageToSend变化且不为空时执行sendMsgAxios useEffect(() => { if (messageToSend.length > 0) { sendMsgAxios() } }, [messageToSend])
第三步:改写原有业务方法
const sendMsgToMe = () => { const { senderIdString, senderId } = props setBtnSendMeIsDisabled(true) axios.get(`${appConfig.URL_REST}user`, { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } }).then(response => { const myNumber = response.data.phoneNumber // 更新状态后useEffect会自动触发sendMsgAxios setMessageToSend([{ from: senderIdString ? senderIdString.number : senderId, to: myNumber, message: messages[counter] }]) }) } const sendMsgToRecipients = () => { const { recipientsNmbs, senderIdString, senderId } = props setBtnSendIsDisabled(true) const msgToSend = recipientsNmbs.map(item => ({ from: senderIdString ? senderIdString.number : senderId, to: item, message: messages[counter] })) setMessageToSend(msgToSend) }
方案2:直接传参调用(更优实现)
核心思路是setState的回调本质是要拿到最新的构造参数,该参数在调用setState前已经构造完成,不需要依赖状态更新后再读取,可直接作为参数传入sendMsgAxios,减少不必要的状态依赖和useEffect监听。
第一步:改造sendMsgAxios
// 改为接收消息列表参数,不依赖外部状态 const sendMsgAxios = (msgList) => { // 原有逻辑直接使用传入的msgList即可 }
第二步:改写业务方法
const sendMsgToMe = () => { const { senderIdString, senderId } = props setBtnSendMeIsDisabled(true) axios.get(`${appConfig.URL_REST}user`, { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } }).then(response => { const myNumber = response.data.phoneNumber const msgToSend = [{ from: senderIdString ? senderIdString.number : senderId, to: myNumber, message: messages[counter] }] setMessageToSend(msgToSend) // 直接调用方法,不需要等待状态更新 sendMsgAxios(msgToSend) }) } const sendMsgToRecipients = () => { const { recipientsNmbs, senderIdString, senderId } = props setBtnSendIsDisabled(true) const msgToSend = recipientsNmbs.map(item => ({ from: senderIdString ? senderIdString.number : senderId, to: item, message: messages[counter] })) setMessageToSend(msgToSend) sendMsgAxios(msgToSend) }
方案选择建议
- 如果
messageToSend仅用于sendMsgAxios逻辑,建议选择方案2,可完全删除messageToSend状态,代码更简洁,无额外依赖。 - 如果
messageToSend还需要用于页面渲染等其他逻辑,两种方案都可,方案2没有额外useEffect依赖,维护成本更低。
内容的提问来源于stack exchange,提问作者Ati
相关产品推荐
相关产品推荐

