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>
      )
    }
  • 相关阅读:
    NET在后置代码中输入JS提示语句(背景不会变白)
    陈广老师C#参考视频 方法的参数传递 总结
    preventDefault和stopPropagation两个方法的区别
    zerobased budgeting: 零基预算法
    JS: 关于自执行的匿名函数(整理)
    通过实例理解javascript 的call()与apply()
    setTimeout注意几点
    js constructor
    canphp的数据库操作
    JS事件监听器
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12806084.html
Copyright © 2011-2022 走看看