zoukankan      html  css  js  c++  java
  • [React] Refactor a render prop component into hooks

    Our <Query /> component is a render prop based component that the <User /> component uses. But because it doesn't render anything, we can actually just change it to a custom hook. Let's create a useQuery hook that returns the state from the hooks the Query component uses and use that instead. But we'll preserve the component so we don't have to refactor everywhere that uses the Query render prop based component as well and we can keep our tests passing as they are.

    function Query({query, variables, normalize = data => data, children}) {
      const client = useContext(GitHub.Context)
      const [state, setState] = useSafeSetState({
        loaded: false,
        fetching: false,
        data: null,
        error: null,
      })
    
      useDeepCompareEffect(
        () => {
          setState({fetching: true})
          client
            .request(query, variables)
            .then(res =>
              setState({
                data: normalize(res),
                error: null,
                loaded: true,
                fetching: false,
              }),
            )
            .catch(error =>
              setState({
                error,
                data: null,
                loaded: false,
                fetching: false,
              }),
            )
        },
        [query, variables],
      )
    
      return children(state)
    }
    
    function User({username}) {
      const {logout} = useContext(GitHubContext)
      const [filter, setFilter] = useState('')
      return (
        <Query
          query={userQuery}
          variables={{username}}
          normalize={normalizeUserData}
        >
          {({fetching, data, error}) =>
            error ? (
              <IsolatedContainer>
                <p>There was an error loading the data</p>
                <pre>{JSON.stringify(error, null, 2)}</pre>
              </IsolatedContainer>
            ) : fetching ? (
              <LoadingMessagePage>Loading data for {username}</LoadingMessagePage>
            ) : data ? (
              <UserContext.Provider value={data}>
                <Container>
                  <Row>
                    <Column width="3">
                      <Profile />
                      <PrimaryButton
                        css={{marginTop: 20,  '100%'}}
                        onClick={logout}
                      >
                        Logout
                      </PrimaryButton>
                      <ButtonLink css={{marginTop: 20,  '100%'}} to="/">
                        Try another
                      </ButtonLink>
                    </Column>
                    <Column width="9">
                      <Text size="subheading">Repositories</Text>
                      <RepoFilter filter={filter} onUpdate={setFilter} />
                      <RepoList filter={filter} />
                    </Column>
                  </Row>
                </Container>
              </UserContext.Provider>
            ) : (
              <IsolatedContainer>I have no idea what's up...</IsolatedContainer>
            )
          }
        </Query>
      )
    }

    Refactor code into hooks:

    function useQuery({query, variables, normalize = data => data}) {
      const client = useContext(GitHub.Context)
      const [state, setState] = useSafeSetState({
        loaded: false,
        fetching: false,
        data: null,
        error: null,
      })
    
      useDeepCompareEffect(
        () => {
          setState({fetching: true})
          client
            .request(query, variables)
            .then(res =>
              setState({
                data: normalize(res),
                error: null,
                loaded: true,
                fetching: false,
              }),
            )
            .catch(error =>
              setState({
                error,
                data: null,
                loaded: false,
                fetching: false,
              }),
            )
        },
        [query, variables],
      )
    
      return state
    }
    
    const Query = ({children, ...props}) => children(useQuery(props))

    We add API 'useQuery' it just return state, instead of rendering the children. And we still keep 'Query' component in case somewhere in the code, we still need to use render prop partten.

    function User({username}) {
      const {logout} = useContext(GitHubContext)
      const [filter, setFilter] = useState('')
    
      const {fetching, data, error} = useQuery({
        query: userQuery,
        variables: {username},
        normalize: normalizeUserData,
      })
    
      return error ? (
        <IsolatedContainer>
          <p>There was an error loading the data</p>
          <pre>{JSON.stringify(error, null, 2)}</pre>
        </IsolatedContainer>
      ) : fetching ? (
        <LoadingMessagePage>Loading data for {username}</LoadingMessagePage>
      ) : data ? (
        <UserContext.Provider value={data}>
          <Container>
            <Row>
              <Column width="3">
                <Profile />
                <PrimaryButton
                  css={{marginTop: 20,  '100%'}}
                  onClick={logout}
                >
                  Logout
                </PrimaryButton>
                <ButtonLink css={{marginTop: 20,  '100%'}} to="/">
                  Try another
                </ButtonLink>
              </Column>
              <Column width="9">
                <Text size="subheading">Repositories</Text>
                <RepoFilter filter={filter} onUpdate={setFilter} />
                <RepoList filter={filter} />
              </Column>
            </Row>
          </Container>
        </UserContext.Provider>
      ) : (
        <IsolatedContainer>I have no idea what's up...</IsolatedContainer>
      )
    }
  • 相关阅读:
    Android实战技巧:深入解析AsyncTask
    Android开发在路上:少去踩坑,多走捷径
    ART:Android 摆脱卡顿的希望?
    搭建Elasticsearch集群的配置
    Docker学习笔记-(5)容器数据管理,链接容器,构建私有库
    Docker学习笔记-(4)Dockerfile
    Docker学习笔记-(3)网络设置
    Docker学习笔记-(2)端口映射
    Docker学习笔记-(1)常用命令
    【架构】Heartbeat高可用服务(2)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12806084.html
Copyright © 2011-2022 走看看