使用子级作为函数时组件未渲染

问题描述 投票:2回答:1

我正在使用react-apollo查询graphQL服务器,并能够成功地将数据与客户端混合。由于将有不止一个地方,因此我将查询数据,我试图创建一个容器(重构)以封装useQuery钩子,以便可以在一个地方使用。

第一次尝试(按预期方式工作)

const HomeContainer = () => {
  const { data, error, loading } = useQuery(GET_DATA_QUERY, {
    variables: DATA_VARIABLES
  });
  const [transformedData, setTransformedData] = useState();

  useEffect(() => {
    if(!!data) {
      const transformedData = someTransformationFunc(data);

      setTransformedData(...{transformedData});
    }
  }, [data]);

  if (loading) {
    return <div>Loading data ...</div>;
  }

  if (error) {
    return <p>Error loading data</p>;
  }
  if (!data) {
    return <p>Not found</p>;
  }

  return <Home transformedData={transformedData} />;
};

我想将查询的不同阶段周围的仪式封装到一个新的容器(加载,错误状态)中,以便减少代码重复。

重构时的第一刺

  • 查询容器在queryvariablescallback中传递。这有责任根据查询的状态(加载,错误或没有数据返回时)返回不同的节点。

const HomeContainer = () => {
  const {data, error, loading} = useQuery(GET_DATA_QUERY, {
    variables: DATA_VARIABLES
  });
  const [transformedData, setTransformedData] = useState();

  const callback = (data) => {
    const transformedData = someTransformationFunc(data);

    setTransformedData(...{
      transformedData
    });
  };

  return ( 
     <QueryContainer 
        query={GET_DATA_QUERY}
        variables={DATA_VARIABLES}
        callback ={callback} 
     >
        <Home transformedData={transformedData} />
     </QueryContainer>
  )
};

const QueryContainer = ({callback, query, variables, children }) => {
  const {data, error, loading } = useQuery(query, {
    variables: variables
  });

  // Once data is updated invoke the callback
  // The transformation of the raw data is handled by the child
  useEffect(() => {
    if (!!data) {
      callback(data);
    }
  }, [data]);

  if (loading) {
    return <div > Loading data... < /div>;
  }

  if (error) {
    return <p > Error loading data < /p>;
  }
  if (!data) {
    return <p > Not found < /p>;
  }

  return children;
};

QueryContainer正在使用useEffect,并在callback返回时调用data。我觉得这有点混乱,并且无法实现封装在父级中并使用callback来交谈和更新子级的目的。

第三次尝试(将孩子用作函数)

摆脱了回调并将数据作为第一个参数传递给children函数。

const HomeContainer = () => {
    return (
        <QueryContainer
            query={GET_DATA_QUERY}
            variables={DATA_VARIABLES}
        >   
           {(data) => {
               const transformedData = someTransformationFunc(data);

                return <Home transformedData={transformedData} />;
           }}

        </QueryContainer>
    )
};

const QueryContainer = ({ query, variables, children }) => {
    const { data, error, loading } = useQuery(query, {
        variables: variables
    });

    if (loading) {
        return <div>Loading data ...</div>;
    }

    if (error) {
        return <p>Error loading data</p>;
    }
    if (!data) {
        return <p>Not found</p>;
    }

    return children(data);
};

我希望它能正常工作,因为当data更新时,新渲染将以data作为参数将子级作为函数调用。但是当我导航到该路线时,我会看到黑屏(没有错误,并且可以看到正确的数据记录到控制台中)如果再次单击该链接,则可以看到已提交给DOM的组件。

不太确定这里发生了什么,想知道是否有人可以对这里发生的事情有所了解。

reactjs graphql react-apollo react-apollo-hooks
1个回答
0
投票

为什么不使用React Context?我会说这将更容易,更有效。

只需创建一个新文件Context.js或任何其他文件,您就可以在这里查询您的数据并根据需要传递它。这将是您的容器:

// Context.js
import React, { createContext } from "react"
import { useQuery } from "@apollo/react-hooks"
import gql from "graphql-tag"

export const QueryContext = createContext()

const QueryContextProvider = ({ children }) => {
  const { loading, error, data } = useQuery(gql`
    {
      ...
    }
  `)
  // Passing the data to the Context provider. 
  // You can pass any state needed.
  return (
    <QueryContext.Provider
      value={{
        loading,
        error,
        data
      }}
    >
      {children}
    </QueryContext.Provider>
  )
}

export default QueryContextProvider

您现在需要使用此上下文包装您的应用程序:

// App.js
import QueryContextProvider from "./Context"

const client = new ApolloClient({
  uri: "your end point"
})

const App = () => {
  return (
    <ApolloProvider client={client}>
      <QueryContextProvider>

        // Your components ...
        <SomeComponent />


      </QueryContextProvider>
    </ApolloProvider>
  )
}

export default App

现在您可以通过整个应用程序获取数据。像这样消耗它:

// SomeComponent.js
import React, { useContext } from "react"
import { QueryContext } from "../Context"

const SomeComponent = () => {
  const { loading, error, data } = useContext(QueryContext)
  if (loading) return <p>Loading...</p>
  if (error) return <p>Error :(</p>

  return data.map(({ args.. }) => (
    <div> 
      ...
    </div>
  ))
}

Edit react useContext-with-useQuery-apollo-graphql

© www.soinside.com 2019 - 2024. All rights reserved.