• [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>
      )
    }
  • 相关阅读:
    MySql行锁等待时间
    日志工具类-Mapper静态调用
    MySql锁机制理解记录
    Flink之TableAPI和SQL(5):表的时间特性
    Flink之TableAPI和SQL(4):表的Sink实现
    Flink之TableAPI和SQL(3):通过TableAPI和SQL表的一些操作(包括查询,过滤,聚集等)
    Flink之TableAPI和SQL(2):表和外部系统的连接方式
    Flink之TableAPI和SQL(1):基本功能描述
    sb 错误
    洛谷 P6189
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12806084.html
Copyright © 2020-2023  润新知