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>
      )
    }
  • 相关阅读:
    解题报告:POJ1852 Ants
    解题报告:POJ2573 Bridge(分析建模)
    POJ 3321 Apple Tree(树状数组模板)
    PAT1139 First Contact
    POJ3259 SPFA判定负环
    HDOJ2586 最近公共祖先模板
    树的直径与最近公共祖先
    字符数组_随机存储
    青鸟资料下载
    软件测试(4)_LoadRunner使用
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12806084.html
Copyright © 2011-2022 走看看