redux-thunk

115 阅读1分钟

redux-thunk

1.在创建strore的时候注册redux-thunk中间件。

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const store = createStore(reducers, applyMiddleware(thunk));

2.使用redux-thunk

//正常发送一个action,但是dispatch中传入的是一个函数,函数中执行异步操作
store.dispatch(getList());

//getList函数
const getList = () => {
    return (dispatch) => {
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, 300);
      }).then(() => {
        dispatch({
          type: 'addList',
          payload: [4, 5, 6],
        });
      });
    };
  };

不使用redux-thunk中间件的时候,dispatch只能发送javascrip对象,使用之后可以发送一个函数,函数会获取一个dispatch对象,使用这个对象和不使用中间件的时候一样。

redux异步处理方案

截屏2022-05-17 下午7.02.50.png

useEffect 异步操作问题

如果在响应回来之前组件被销毁了会怎样?

问题的核心在于,在组件卸载后依然调用了 setValue(data.value)和 setLoading(false)来更改状态。因此一个简单的办法是标记一下组件有没有被卸载,可以利用 useEffect的返回值。

useEffect( => {
  let isUnmounted = false;
  (async => {
    const res = await fetch(SOME_API);
    const data = await res.json;
    if (!isUnmounted) {
      setValue(data.value);
      setLoading(false);
    }
  });
  return => {
  isUnmounted = true;
  }
}, []); 

AbortController中断请求:

useEffect( => {
  let isUnmounted = false;
  const abortController = new AbortController; // 创建
  (async => {
    const res = await fetch(SOME_API, {
    singal: abortController.singal, // 当做信号量传入
    });
    const data = await res.json;
    if (!isUnmounted) {
      setValue(data.value);
      setLoading(false);
    }
  });
  return => {
    isUnmounted = true;
    abortController.abort; // 在组件卸载时中断
  }
}, []);

singal实现中断异步请求:

import React, { Component } from 'react';
import axios from 'axios';
​
class Example extends Component {
  signal = axios.CancelToken.source();
​
  state = {
    isLoading: false,
    user: {},
  }
  
  componentDidMount() {
    this.onLoadUser();
  }
  
  componentWillUnmount() {
    this.signal.cancel('Api is being canceled');
  }
  
  onLoadUser = async () => {
    try {
      this.setState({ isLoading: true });
      const response = await axios.get('https://randomuser.me/api/', {
        cancelToken: this.signal.token,
      })
      this.setState({ user: response.data, isLoading: true });
    } catch (err) {
      if (axios.isCancel(err)) {
        console.log('Error: ', err.message); // => prints: Api is being canceled
      } else {
        this.setState({ isLoading: false });
      }
    }
   } 
    render() {
      return (
        <div>
          <pre>{JSON.stringify(this.state.user, null, 2)}</pre>
        </div>
      )
    }
 
}