You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React组件卸载时仅Dispatch Action的实现方案求助

解决方案:组件卸载时触发updateUser Action

问题分析

你当前的代码存在几个关键问题:

  1. 第一个useEffect里的isMounted逻辑完全错误——清理函数里先把isMounted设为false,紧接着判断isMounted,导致后续的dispatch代码永远不会执行。
  2. 第二个useEffect依赖数组为空,会触发闭包陷阱:清理函数捕获的currentUser和user是组件挂载时的初始值,不是卸载时的最新值,没法正确判断内容是否修改。
  3. phoneExtension是单独维护的状态,没有同步到user对象里,卸载时该字段的修改会丢失,不会被dispatch到store。

修正后的代码

import React, { useEffect, useState } from 'react';
import '../User.scss';
import iconPhone from '../../../images/icon-phone.png';
import iconMail1 from '../../../images/icon-mail-01.png';
import iconMessageTextSquare1 from '../../../images/icon-message-text-square-01.png';
import { useAppDispatch, useAppSelector } from '../../../hooks/storeHooks';
import { UserDetails } from '../model/userDetails';
import { updateUser } from '../UserSlice';
import { isEqual } from 'lodash';

const Profile: React.FC = () => {
  const dispatch = useAppDispatch();

  const currentUser = useAppSelector((state) => state.user.currentUser);
  // 初始化时合并phoneExtension到user状态
  const initialUserState = currentUser 
    ? { ...currentUser, phoneExtension: currentUser.phoneExtension || '000' } 
    : undefined;
  const [user, setUser] = useState<UserDetails & { phoneExtension?: string } | undefined>(initialUserState);

  const handleInputChange = (id: string, value: string) => {
    setUser((prevUser) => ({
      ...(prevUser as UserDetails & { phoneExtension?: string }),
      [id]: value,
    }));
  };

  // 正确的useEffect:依赖包含currentUser和user,确保清理函数捕获最新值
  useEffect(() => {
    // 清理函数在组件卸载时执行
    return () => {
      if (currentUser?.id && user) {
        // 对比当前store值和本地修改后的值
        const updatedUser = { ...user };
        // 移除phoneExtension单独字段(如果UserDetails不包含的话,根据实际模型调整)
        delete updatedUser.phoneExtension;
        
        if (!isEqual(currentUser, updatedUser)) {
          console.log('Changes detected. Dispatching update.');
          dispatch(updateUser({ id: currentUser.id, user: updatedUser }));
        } else {
          console.log('No changes detected.');
        }
      }
    };
  }, [currentUser, user, dispatch]); // 必须添加所有用到的依赖

  return (
    <div className='flex flex-row flex-grow profile-block'>
      <div className='card profile-card'>
        <div className='header'>
          <span className='title'>Profile</span>
          <div>update your personal and company details here.</div>
        </div>
        <div className='body'>
          <div className='profile-info'>
            <div className='protext'>
              <div className='text'>Personal info</div>
              <p>Personal details and profile picture</p>
            </div>
            <div className='card'>
              <form className='register-form'>
                <div className='form-row'>
                  <div className='form-col'>
                    <label htmlFor='firstName'>First Name:</label>
                    <input
                      type='text'
                      id='firstName'
                      className='custom-input'
                      value={user?.firstName || ''}
                      onChange={(e) => handleInputChange('firstName', e.target.value)}
                      readOnly={false}
                    />
                  </div>
                  <div className='form-col'>
                    <label htmlFor='lastName'>Last Name:</label>
                    <input
                      type='text'
                      id='lastName'
                      className='custom-input'
                      value={user?.lastName || ''}
                      onChange={(e) => handleInputChange('lastName', e.target.value)}
                    />
                  </div>
                </div>
                <div className='form-row'>
                  <div className='form-col full-col'>
                    <label htmlFor='jobtitle'>Job Title:</label>
                    <input
                      type='text'
                      id='jobtitle'
                      className='custom-input'
                      value={user?.jobTitle || ''}
                      onChange={(e) => handleInputChange('jobTitle', e.target.value)}
                    />
                  </div>
                </div>
                <div className='form-row'>
                  <div className='form-col col60'>
                    <label htmlFor='phoneNumber'>Office Number</label>
                    <div className='input-group'>
                      <div className='icon-block'>
                        <img src={iconPhone} alt='icon phone' />
                      </div>
                      <input
                        type='text'
                        id='phoneNumber'
                        className='custom-input'
                        value={user?.phoneNumber || ''}
                        onChange={(e) => handleInputChange('phoneNumber', e.target.value)}
                      />
                    </div>
                  </div>
                  <div className='form-col col40'>
                    <label htmlFor='phoneExtension'>Phone Extension:</label>
                    <input
                      type='text'
                      id='phoneExtension'
                      className='custom-input'
                      value={user?.phoneExtension || '000'}
                      onChange={(e) => handleInputChange('phoneExtension', e.target.value)}
                    />
                  </div>
                </div>
              </form>
            </div>
          </div>
          <br />
          <div className='divider'></div>
          <br />
          <br />
          <div className='profile-info'>
            <div className='protext'>
              <div className='text'>Notification Contact Information</div>
              <p>Details here will be blah blah blah for contact information for notifications. </p>
            </div>
            <div className='card'>
              <form className='register-form'>
                <div className='form-row'>
                  <div className='form-col full-col'>
                    <label htmlFor='notifyEmail'>Notify me by email</label>
                    <div className='input-group'>
                      <div className='icon-block'>
                        <img src={iconMail1} alt='icon email' />
                      </div>
                      <input
                        type='text'
                        id='notifyEmail'
                        className='custom-input'
                        value={user?.email || ''}
                        onChange={(e) => handleInputChange('email', e.target.value)}
                      />
                    </div>
                  </div>
                  <div className='form-col full-col'>
                    <label htmlFor='notifySms'>Notify me by sms</label>
                    <div className='input-group'>
                      <div className='icon-block'>
                        <img src={iconMessageTextSquare1} alt='icon sms' />
                      </div>
                      <input
                        type='text'
                        id='notifySms'
                        className='custom-input'
                        value={user?.phoneNumber || ''}
                        onChange={(e) => handleInputChange('phoneNumber', e.target.value)}
                      />
                    </div>
                  </div>
                  <div className='form-col full-col'>
                    <label htmlFor='notifyDialer'>Notify me by dialer</label>
                    <div className='input-group'>
                      <div className='icon-block'>
                        <img src={iconMessageTextSquare1} alt='icon dialer' />
                      </div>
                      <input
                        type='text'
                        id='notifyDialer'
                        className='custom-input'
                        value={user?.dialer || ''}
                        onChange={(e) => handleInputChange('dialer', e.target.value)}
                      />
                    </div>
                  </div>
                  <div className='form-col full-col'>
                    <label htmlFor='notifyPager'>Notify me by pager</label>
                    <div className='input-group'>
                      <div className='icon-block'>
                        <img src={iconMessageTextSquare1} alt='icon pager' />
                      </div>
                      <input
                        type='text'
                        id='notifyPager'
                        className='custom-input'
                        value={user?.pager || ''}
                        onChange={(e) => handleInputChange('pager', e.target.value)}
                      />
                    </div>
                  </div>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Profile;

关键修正点

  1. 合并状态:把phoneExtension合并到user状态中,避免单独维护导致的修改丢失问题。
  2. 修复闭包问题:useEffect的依赖数组添加currentUser、user和dispatch,确保清理函数能捕获到最新的状态值。
  3. 移除无效的isMounted判断:清理函数本身就是在组件卸载时执行,不需要额外判断挂载状态。
  4. 修正输入ID:把重复的notifySmsID改为对应的notifyDialer、notifyPager,避免DOM元素ID冲突。

内容的提问来源于stack exchange,提问作者radhey_mishra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:29:51