如何从自定义钩子传递状态数据以响应组件?

时间:2020-06-03 16:08:27

标签: reactjs react-hooks

我有一个自定义钩子(useFetch),它将URL作为输入并从该URL中获取数据并返回数据。我想在其他组件上实现Spinner(已经由Spinner组成),并且尝试通过为Spinner的isLoadingsetIsLoading设置状态。 我的自定义钩子代码:

import { useState, useEffect } from 'react';

    const useFetch = (url) => {
      const [dataArray, setData] = useState([]);
      const [isLoading, setIsLoading] = useState(false);
      useEffect(() => {
        try {
          const fetchData = async () => {
            setIsLoading(true);
            const res = await fetch(url);
            const dataArray = await res.json();
            setData(dataArray.data);
          };
          fetchData();
        } catch (err) {
          console.error(err);
        }
        setIsLoading(false);
      }, [url]);

      return dataArray;
    };

    export default useFetch;

这是我要实现微调器的组件。

import React, { useState } from 'react';
import CONSTANTS from '../../constants/constants';
import CompanyLists from '../../components/company-lists/CompanyLists';
import Pagination from '../../components/pagination/Pagination';
import useFetch from '../../components/effects/use-fetch.effect';
import Spinner from '../../components/spinner/Spinner';
const CompanyListing = () => {
  const [counter, setCounter] = useState(1);
  const companies = useFetch(`${CONSTANTS.BASE_URL}/companies?page=${counter}`);

  return (
    <>
      <Container>
        <div style={userStyle}>
          {companies ? companies.map((company) => <CompanyLists key={company.id} {...company} />) : 'No companies'}
        </div>
        <Pagination props={companies} counter={counter} name="companies" setCounter={setCounter} />
        <Spinner />
      </Container>
    </>
  );
};
const userStyle = {
  display: 'grid',
  gridTemplateColumns: 'repeat(1, 1fr)',
  gridGap: '1rem',
};
export default CompanyListing;

这里的问题是:如何将那些加载状态从挂钩发送到CompanyListing组件。任何帮助将不胜感激。

编辑:

我还有其他组件也调用相同的钩子,我希望它们不会损坏。正如我没有提到原始问题。 我的另一种情况:

const jobsUrl = `${CONSTANTS.BASE_URL}/jobs?page=${counter}`;
  const jobs = useFetch(jobsUrl);

AND

const { city, company_name, company_id, department, description, job_type, position, posted_at, url } = useFetch(
    `${CONSTANTS.BASE_URL}/jobs/${id}`
  );

在这两种情况下我该如何破坏?

4 个答案:

答案 0 :(得分:1)

您还需要从挂钩中返回isLoading

import { useState, useEffect } from 'react';

    const useFetch = (url) => {
      const [dataArray, setData] = useState([]);
      const [isLoading, setIsLoading] = useState(false);
      useEffect(() => {
        try {
          const fetchData = async () => {
            setIsLoading(true);
            const res = await fetch(url);
            const dataArray = await res.json();
            setData(dataArray.data);
          };
          fetchData();
        } catch (err) {
          console.error(err);
        }
        setIsLoading(false);
      }, [url]);

      return {dataArray, isLoading};
    };

export default useFetch;

像这样在您的组件中使用

import React, { useState } from 'react';
import CONSTANTS from '../../constants/constants';
import CompanyLists from '../../components/company-lists/CompanyLists';
import Pagination from '../../components/pagination/Pagination';
import useFetch from '../../components/effects/use-fetch.effect';
import Spinner from '../../components/spinner/Spinner';
const CompanyListing = () => {
  const [counter, setCounter] = useState(1);
  const {dataArray: companies, isLoading} = useFetch(`${CONSTANTS.BASE_URL}/companies?page=${counter}`);

  return (
    <>
      <Container>
        <div style={userStyle}>
          {companies ? companies.map((company) => <CompanyLists key={company.id} {...company} />) : 'No companies'}
        </div>
        <Pagination props={companies} counter={counter} name="companies" setCounter={setCounter} />
        {isLoading && <Spinner />}
      </Container>
    </>
  );
};
const userStyle = {
  display: 'grid',
  gridTemplateColumns: 'repeat(1, 1fr)',
  gridGap: '1rem',
};
export default CompanyListing;

答案 1 :(得分:1)

从您的自定义钩子中,您都可以返回

/f

同时破坏两者

   return {companies: dataArray, isLoading };

答案 2 :(得分:1)

首先,您可能需要稍微改变useFetch的效果才能正确更新isLoading。然后您可以同时返回dataArrayisLoading

import { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [dataArray, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  useEffect(() => {
    try {
      const fetchData = async () => {
        setIsLoading(true);
        const res = await fetch(url);
        const dataArray = await res.json();
        setData(dataArray.data);
      };
      await fetchData();
    } catch (err) {
      console.error(err);
    } finally {
      setIsLoading(false);
    }
  }, [url]);

  return [dataArray, isLoading];
};

export default useFetch;

并按如下所示使用它:

const [companies, isLoading] = useFetch(`${CONSTANTS.BASE_URL}/companies?page=${counter}`);

答案 3 :(得分:1)

您在这里不需要任何特殊的东西。只需从isLoading钩中将dataArray返回useFetch状态即可。

如编辑中所述,您需要useFetch才能更重用,并根据API响应返回不同格式的数据,因此状态应初始化为null。

import { useState, useEffect } from 'react';

const useFetch = (url) => {
  // it is best to initialize the state as null because response.data
  // may be an object or an array depending on the API response

   const [data, setData] = useState(null);

   const [isLoading, setIsLoading] = useState(false);

   useEffect(() => {
     try {
        const fetchData = async () => {
        setIsLoading(true);
        const res = await fetch(url);
        const value = await res.json();

        setData(value.data);
        };
          fetchData();
        } catch (err) {
          console.error(err);
        }
        setIsLoading(false);
   }, [url]);

   return {data, isLoading};
};

export default useFetch;

在要使用自定义钩子的组件中,可以进行分解 dataisLoading的值,但要进一步从返回的数据中解构值,我们必须检查data是否为null

// destructure the values
const {data, isLoading} = useFetch(`${CONSTANTS.BASE_URL}/companies?page=${counter}`);

// in this case data will be an array based on your API response
// please make sure to check data.length before trying to loop over
// and render the content, for example

return (
 <div>
  {
    data.length && data.map(company => (
      <CompanyLists key={company.id} {...company} />
    ));
  }
 </div>

)

对于第二种情况,您将使用useFetch(`${CONSTANTS.BASE_URL}/jobs/${id}`);来获取数据,您必须在进一步销毁之前检查返回的数据是否不为null。例子


const { data, isLoading } = useFetch(`${CONSTANTS.BASE_URL}/jobs/${id});

if (isLoading) {
  return <div>Loading...</div>
}

if (data) {
  const { 
      city, 
      company_name, 
      company_id, 
      department, 
      description,
      job_type, position, posted_at, url } = data;


  return (
    // your jsx code
    // for example
    <h3>{company_name}</h3>
    <p>{department}</p>

  )
}