反应useEffect和异步获取

时间:2019-09-29 09:01:34

标签: javascript reactjs react-hooks

这是我的代码:


const useMyFetch = (url, options) => 
{
  const [response, setResponse]   = React.useState(null);

  React.useEffect(() => 
  {
    console.log("going to fetch ", url);

    fetch(url, options).then(async function(response) 
    {
      var json = await response.json();
      setResponse(json.message);
    });

  }, [ url ]); 

  return response;
};



function Example() 
{
  const res = useMyFetch("https://dog.ceo/api/breeds/image/random", { method: 'GET' });

  if (!res) 
  {
    return <div>loading...</div>
  }

  return <img src={res} alt="an image" />;
}


看起来一切都很好...除了当我将useEffect的第二个参数从[url]替换为[url,options]时。 当存在“选项”时,我们将进入众所周知的无限循环……但是将其包含在此数组中是合乎逻辑的。怎么了 谢谢

3 个答案:

答案 0 :(得分:1)

{ method: 'GET' }定义为常量对象,以使options参数始终相同,这是一个示例:

const options = { method: 'GET' };
function Example() {
  const res = useMyFetch("https://dog.ceo/api/breeds/image/random", options);
  ...
}

否则,由于optionsuseMyFetch,因此每次调用{ method: 'GET' } === { method: 'GET' }时,false将被视为已更改。

答案 1 :(得分:0)

查找要测试的网址show the image 它应该返回setResponse您想要的内容

const useMyFetch = (url, options) => 
{
  const [response, setResponse]   = React.useState(null);

  React.useEffect(() => 
  {
    console.log("going to fetch ", url);

    fetch(url, options).then(async (response)=> 
    {
      var json = await response.json();
       return setResponse(json.message);
    });

  }, [ url ]); 

  return response;
};



function Example() 
{
  const res = useMyFetch("https://dog.ceo/api/breeds/image/random", { method: 'GET' });

  if (!res) 
  {
    return <div>loading...</div>
  }

  return <img src={res} alt="an image" />;
}


export default Example;

答案 2 :(得分:0)

正如@Titus所提到的,这是因为{ method: 'GET' }在每个新渲染中都存在参考差异。但是我相信,将组件移出现实生活中不够灵活。需要将令牌传递到标头或其他任何动态计算是预期的要求,对吧?

选项1。我们可以使用JSON.stringify将参数对象作为字符串传递:

function useMyFetch(url, options) {
  useEffect(() => {
  }, [url, JSON.stringify(options)])
} 

选项2。我们可以使用useRefstore previous props并使用自定义比较:

function useMyFetch(url, options) {
  const prevOptions = useRef(null);
  useEffect(() => {
   ...
   prevOptions.current = options;
  }, [url, customCompare(options, prevOptions.current)])
} 

选项3。最后,我可以创建自定义钩子,如果所有嵌套属性均相等,则该钩子将返回引用相同的对象:

function useObject(obj) {
  const prevObj = useRef(obj);
  const isEqual = _.isEqual(prevObj.current, obj);
  useEffect(() => {
    prevObj.current = obj;
  }, [isEqual]);
  return isEqual ? prevObj.current : obj;
}

,以后用作

function Example() 
{
  const requestOptions = useObject({ method: 'GET' });
  const res = useMyFetch("https://dog.ceo/api/breeds/image/random", requestOptions);

  if (!res) 
  {
    return <div>loading...</div>
  }

  return <img src={res} alt="an image" />;
}

选项4。最直接的方法是将对象options分解为原始值:

function useMyFetch(url, options) {
  const {method, headers: {contentType} = {} , ...rest } = options;
  useEffect(() => {
  }, [url, method, contentType, JSON.stringify(rest)]);
}

我相信虽然此方法比上面的方法更为详尽,但它会更快一些,特别是如果rest通常为空(没有多余的标头)。