博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[React] Refactor a Class Component with React hooks to a Function
阅读量:4622 次
发布时间:2019-06-09

本文共 5229 字,大约阅读时间需要 17 分钟。

We have a render prop based class component that allows us to make a GraphQL request with a given query string and variables and uses a GitHub graphql client that is in React context to make the request. Let's refactor this to a function component that uses the hooks useReducer, useContext, and useEffect.

 

Class Based Component:

import {Component} from 'react'import PropTypes from 'prop-types'import isEqual from 'lodash/isEqual'import * as GitHub from '../../../github-client'class Query extends Component {  static propTypes = {    query: PropTypes.string.isRequired,    variables: PropTypes.object,    children: PropTypes.func.isRequired,    normalize: PropTypes.func,  }  static defaultProps = {    normalize: data => data,  }  static contextType = GitHub.Context  state = {loaded: false, fetching: false, data: null, error: null}  componentDidMount() {    this._isMounted = true    this.query()  }  componentDidUpdate(prevProps) {    if (      !isEqual(this.props.query, prevProps.query) ||      !isEqual(this.props.variables, prevProps.variables)    ) {      this.query()    }  }  componentWillUnmount() {    this._isMounted = false  }  query() {    this.setState({fetching: true})    const client = this.context    client      .request(this.props.query, this.props.variables)      .then(res =>        this.safeSetState({          data: this.props.normalize(res),          error: null,          loaded: true,          fetching: false,        }),      )      .catch(error =>        this.safeSetState({          error,          data: null,          loaded: false,          fetching: false,        }),      )  }  safeSetState(...args) {    this._isMounted && this.setState(...args)  }  render() {    return this.props.children(this.state)  }}export default Query

 

Conver props:

// From static propTypes = {    query: PropTypes.string.isRequired,    variables: PropTypes.object,    children: PropTypes.func.isRequired,    normalize: PropTypes.func,  }  static defaultProps = {    normalize: data => data,  }// To:function Query ({query, variables, children, normalize = data => data}) {}

 

Conver Context:

// Fromstatic contextType = GitHub.Context...const client = this.context// To:import {useContext} from 'react'function Query ({query, variables, children, normalize = data => data}) {  const clinet = useContext(GitHub.Context)}

 

Conver State:

I don't like to cover each state prop to 'useState' style, it is lots of DRY, instead, using useReducer is a better & clean apporach.

// Fromstate = {loaded: false, fetching: false, data: null, error: null}//To:  import {useContext, useReducer} from 'react'  ...  const [state, setState] = useReducer(    (state, newState) => ({...state, ...newState}),     defaultState)

 

Conver side effect:

// From:  componentDidMount() {    this._isMounted = true    this.query()  }  componentDidUpdate(prevProps) {    if (      !isEqual(this.props.query, prevProps.query) ||      !isEqual(this.props.variables, prevProps.variables)    ) {      this.query()    }  }  componentWillUnmount() {    this._isMounted = false  }  query() {    this.setState({fetching: true})    const client = this.context    client      .request(this.props.query, this.props.variables)      .then(res =>        this.safeSetState({          data: this.props.normalize(res),          error: null,          loaded: true,          fetching: false,        }),      )      .catch(error =>        this.safeSetState({          error,          data: null,          loaded: false,          fetching: false,        }),      )  }// To:  useEffect(() => {    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]) // trigger the effects when 'query' or 'variables' changes

 

Conver render:

// From:  render() {    return this.props.children(this.state)  }// To:function Query({children ... }) { ... return children(state);    }

 

-----

 

Full Code:

import {useContext, useReducer, useEffect} from 'react'import PropTypes from 'prop-types'import isEqual from 'lodash/isEqual'import * as GitHub from '../../../github-client'function Query ({query, variables, children, normalize = data => data}) {  const client = useContext(GitHub.Context)  const defaultState = {loaded: false, fetching: false, data: null, error: null}  const [state, setState] = useReducer(    (state, newState) => ({...state, ...newState}),    defaultState)  useEffect(() => {    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]) // trigger the effects when 'query' or 'variables' changes  return children(state)}export default Query

 

转载于:https://www.cnblogs.com/Answer1215/p/10393228.html

你可能感兴趣的文章
大端小端
查看>>
IntelliJ IDEA 把java项目导出成可执行的jar
查看>>
DynamicReports
查看>>
鼠标经过图像改变实现
查看>>
每日站立会议个人博客五
查看>>
ddd
查看>>
死磕 java同步系列之AQS起篇
查看>>
利用Lucene把文本的字体格式进行改动,然后输出到一个新的文件里
查看>>
[Openstack] Expecting an auth URL via either --os-auth-url or env[OS_AUTH_URL]
查看>>
How to Create Modifiers Using the API QP_MODIFIERS_PUB.PROCESS_MODIFIERS
查看>>
待飞笔记(第一天 )
查看>>
解惑好文:移动端H5页面高清多屏适配方案
查看>>
traefik添加多证书
查看>>
PhantomJs 笔记
查看>>
js设计模式--语言类型
查看>>
C#多线程之二:ManualResetEvent和AutoResetEvent
查看>>
忽略UserInterfaceState.xcuserstate
查看>>
ReactNative--Flexbox布局
查看>>
java实现读取文件大全
查看>>
[Cordova] 无法显示Alert视窗
查看>>