如何在 React 组件中包装方法

How do I wrap methods in react components

我有很多函数看起来像这样

  doSomething = async (...) => {
    try {
      this.setState({loading: true});

      ...
      var result = await Backend.post(...);
      ...

      this.setState({loading: false});
    } catch(err) {
      this.setState({error: err});
    }
  }

基本上我有 2 个变量加载和错误,我必须为很多函数管理这些变量,并且代码对于所有这些函数基本上是相同的。由于 javascript 中没有装饰器,而且我不希望为此安装任何实验性库,我如何包装此函数以从上面删除重复的 setStates ?

这是我目前的方式,我将函数作为参数传递。

我们有很多 API,从后端获取数据,我们必须处理错误并对数据做一些事情。

只是服务的数据不同,处理错误是一样的

private processServiceResponse(resp: any, doSthWithData: (data: any) => void) {
    let { errors } = resp;
    if (this.hasError(errors)) {
      this.handleServiceErr(errors);
      return;
    }
    let data = resp;
    if (resp && resp.data) {
      data = resp.data;
    }
    doSthWithData(data);
  }

这是我将函数作为参数传递的方式。

let rest1 = service1.getData();
processServiceResponse(rest1,(data)=>{
//only need to focus with processing data.
})

PS: 打字稿编码。

您可以使用高阶函数(将另一个函数作为参数的函数)使常见的加载和错误功能可重用。它非常类似于装饰器模式。例如:

const doSomething = withLoadingAndErrorHandling(Backend.post, this.setState);


function withLoadingAndErrorHandling(fn, setState) {
    return async function(...args) {
       try {
          setState({loading: true});
          var result = await fn(args); 
          setState({loading: false});
          return result;
        } catch(err) {
          setState({error: err});
        }
    }

}

如果你使用的是函数组件,你可以自定义一个钩子来避免重复代码

//useFetch.js

import { useState, useEffect } from 'react';
import axios from 'axios';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
      setLoading('loading...')
      setData(null);
      setError(null);
      const source = axios.CancelToken.source();
      axios.get(url, { cancelToken: source.token })
      .then(res => {
          setLoading(false);
          //checking for multiple responses for more flexibility 
          //with the url we send in.
          res.data.content && setData(res.data.content);
          res.content && setData(res.content);
      })
      .catch(err => {
          setLoading(false)
          setError('An error occurred. Awkward..')
  })
      return () => {
          source.cancel();
      }
  }, [url])

   return { data, loading, error }

export default useFetch;

用法:

import useFetch from './useFetch';
import './App.css';

function App() {
  const { data: quote, loading, error } = 
useFetch('https://api.quotable.io/random')

  return (
    <div className="App">
      { loading && <p>{loading}</p> }
      { quote && <p>"{quote}"</p> }
      { error && <p>{error}</p> }
    </div>
  );
}

export default App;