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>
      )
    }
  • 相关阅读:
    第8章 降维
    第7章 集成学习和随机森林
    JS利用async、await处理少见的登录业务逻辑
    SQL SERVER 实现多行转多列
    Mysql函数----控制流函数介绍
    继承----静态代码快、构造方法、代码块、普通方法的执行顺序
    RBAC----基于角色的访问权限控制
    秋招-----思特沃克视频面试总结
    tomcat启动失败的三种方法
    索引之----mysql联合索引
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12806084.html
Copyright © 2011-2022 走看看