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

React Native函数式组件内存泄漏问题求助:触发“无法在已卸载组件上更新状态”警告

Hey there! That warning pops up because your async API call for the job detail finishes after you've navigated away from the JobDetailScreen (so the component is unmounted), and then the saga tries to update the Redux state tied to that unmounted component. Let's fix this properly by canceling both the saga task and the underlying API request when the component unmounts.


Step 1: Add a Cancel Action Type

First, let's add a new action type to handle canceling the single job request:

// jobdetail.type.js
export const GET_SINGLE_JOB = "GET_SINGLE_JOB";
export const CANCEL_SINGLE_JOB = "CANCEL_SINGLE_JOB"; // Add this line

Step 2: Create the Cancel Action

Add the corresponding action creator:

// jobdetail.action.js
import * as types from "./jobdetail.type";

export const get_single_jobs = (data) => ({ 
  type: types.GET_SINGLE_JOB, 
  payload: data, 
});

// Add this cancel action
export const cancel_single_job = () => ({ 
  type: types.CANCEL_SINGLE_JOB, 
});

Step 3: Update the Saga to Support Cancellation

Modify your saga to listen for the cancel action, cancel the ongoing API request, and stop any state updates:

// jobdetail.saga.js
import { takeLatest, call, put, take, race, CancelledError } from "redux-saga/effects";
import axios from 'axios'; // Import axios for cancel token
import SinglejobsServices from './jobdetail.services';
import * as types from './jobdetail.type';
import * as loadertypes from '../loader/loader.type';

function* get_single_jobs_service(payload) {
  // Create an axios cancel token to abort the API request if needed
  const cancelSource = axios.CancelToken.source();
  
  try { 
    yield put({ type: loadertypes.LOADERSTART});
    
    // Race the API call against the cancel action
    const { response, cancelSignal } = yield race({
      response: call(SinglejobsServices.list, payload, cancelSource),
      cancelSignal: take(types.CANCEL_SINGLE_JOB)
    });

    // If cancel was triggered, abort the request and exit early
    if (cancelSignal) {
      cancelSource.cancel("Request cancelled: component unmounted");
      yield put({ type: loadertypes.LOADERSTOP});
      return;
    }

    // Handle the API response as before
    if(response.status == false){
      yield put({ type: types.SINGLE_JOBS_ERROR, response });
      yield put({ type: loadertypes.LOADERSTOP});
    }else{
      yield put({ type: types.SET_SINGLE_JOB, response });
      yield put({ type: loadertypes.LOADERSTOP});
    }
  } catch(error) { 
    // Ignore cancellation errors
    if (error instanceof CancelledError || axios.isCancel(error)) {
      console.log("Single job request cancelled");
      yield put({ type: loadertypes.LOADERSTOP});
      return;
    }
    
    // Handle other errors normally
    let response = error.response.data;
    yield put({ type: types.SINGLE_JOBS_ERROR, response });
    yield put({ type: loadertypes.LOADERSTOP});
  }
}

export default function* watchSinglejobs() { 
  // Use takeLatest to automatically cancel previous tasks if a new request comes in
  yield takeLatest(types.GET_SINGLE_JOB, get_single_jobs_service);
}

Step 4: Update the Service to Accept Cancel Token

Modify your API service to use the cancel token:

// Jobdetail.services.js
import axios from "axios";
import {API_URL} from '../../config/constant';

function services(){
  // Add cancelSource as a parameter
  const list = (request, cancelSource) => { 
    let req = request.payload;
    const config = { 
      method: 'get',
      url: API_URL + '/jobs/details/'+req.job_id,
      headers: { 
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${req.user.userToken}` 
      },
      cancelToken: cancelSource.token // Attach the cancel token
    }
    return axios(config)
    .then(response => { 
      let result = response.data;
      return result;
    })
  }
  return { list, };
}

const SinglejobsServices = services();
export default SinglejobsServices;

Step 5: Add Cleanup to the Component

Finally, update your JobDetailScreen to dispatch the cancel action when the component unmounts:

// JobDetailScreen.js
import { useDispatch } from 'react-redux';
import { get_single_jobs, cancel_single_job } from './jobdetail.action'; // Import the cancel action

// ... inside your component
const dispatch = useDispatch();

useEffect(() => { 
  let data = {} 
  data.user = login 
  data.job_id = route.params.job_id 
  dispatch(get_single_jobs(data)); 

  // Cleanup function: runs when component unmounts
  return () => {
    dispatch(cancel_single_job());
  };
},[dispatch, login, route.params.job_id]); // Add dependencies to the effect

Why This Works

  • When you navigate away from the screen, the component's cleanup function dispatches the CANCEL_SINGLE_JOB action.
  • The saga catches this action via the race effect, cancels the ongoing API request using axios's cancel token, and exits without updating the Redux state.
  • This prevents any state updates from happening after the component has unmounted, eliminating the memory leak warning.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 22:39:06