美文网首页
React快速上手6-Context、高阶组件和Hooks

React快速上手6-Context、高阶组件和Hooks

作者: xinyiyake | 来源:发表于2019-03-20 14:28 被阅读0次

Context API

react组件中经常会遇到这样一种情况,由于组件嵌套层数过多导致state管理复杂,props传递不方便,这个时候你可以使用redux之流来进行状态管理,但是如果只是个别state难以管理,redux可能有点杀鸡用牛刀了,这时你可以考虑试一下context API。
在react官网文档中是这样来介绍context的:

Context provides a way to pass data through the component tree without having to pass props down manually at every level.(Context提供了一种通过组件树传递数据的方法,而无需在每一级手动传递props。)
下面我们一步一步来看一下如何去使用context

  1. 我们通过React.createContext()创建一个context对象:
const { Provider, Consumer } = React.createContext()
  1. 然后创建一个返回Provider组件的包装器组件,并添加要从中访问上下文的所有组件作为子组件:
class Container extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }
  render() {
    return (
      <Provider value={{ 
          state: this.state 
      }}>
        {this.props.children}
      </Provider>
    )
  }
}

class Calculator extends React.Component {
  render() {
    return (
      <Container>
        <Button />
      </Container>
    )
  }
}

Container组件将是一个全局的Provider,您还可以创建较小的context。

  1. 在Provider中包含的组件内部,使用Consumer组件来使用context:
class Button extends React.Component {
  render() {
    return (
      <Consumer>
        {context => <button>{context.state.count}</button>
      </Consumer>
    )
  }
}

4.您还可以将函数作为传递值给Provider,而Consumer可以使用这些函数来更新context的state:

class Container extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }
  render() {
    return (
      <Provider value={{ 
          state: this.state,
          addHandle : ()=>{this.setState({count: this.state.count+1})}
      }}>
        {this.props.children}
      </Provider>
    )
  }
}
/**...**/
<Consumer>
  {(context) => (
    <button onClick={context.addHandle}>
      {context.state.count}
    </button>
  )}
</Consumer>

这样一来,你就可以很好的解决了多层组件套用的问题。
关于context更多的用法,可以参考react官方文档

高阶组件基础应用(HOC)

高阶组件在react中是一个非常有用的概念,它有点类似于javascript中的高级函数,比如说Array.map(),接受函数作为一个参数,在react中,如果一个组件接受一个组件然后返回一个组件,那么这个组件就可以被称为高阶组件。
一般来说,高阶组件经常用来创建高可复用性的代码,举个例子,我们可以给一个组件去给一个组件添加一些方法或者属性,或者是一个redux store。
下面将给出一个最基础的例子:

const withColor = (Element) =>{
    return (
        (props) => <Element {...props} color="red" />
    )
}

withColor是一个组件,它传递一个组件作为参数,返回一个组件并给这个组件设置了color为'red'。
接下来我们使用withColor这个高级组件:

const Button = () => {
  return <button>test</button>
}
const ColoredButton = withColor(Button)

最后我们在渲染出ColoredButton组件:

function App() {
  return (
    <div className="App">
      <h1>Hello</h1>
      <ColoredButton />
    </div>
  )
}

这只是一个最基础的高阶组件的示例,但希望在将这些概念应用于更复杂的场景之前,能够对理解高阶组件的要点有所帮助。

Hooks

Hooks是在React 16.7中引入的新特性,它的作用是能够让我们在函数定义的组件中使用state和生命周期事件,使得函数组件有一个处理事件的好方法。

1. 获取state

我们使用useState()API,创建一个新的state变量,并且可以修改它。 useState()接受state项的初始值,并返回一个包含state变量的数组,以及您调用以更改状态的方法。 由于它返回一个数组,我们使用数组解构来访问每个单独的项,如下所示:

import React, { useState } from 'react'

const Counter = () => {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>总数:{count}</p>
      <button onClick={() => setCount(count + 1)}>点击+1</button>
    </div>
  )
}

ReactDOM.render(<Counter />, document.getElementById('app'))

你可以尽可能的调用useState(),来创建你所需要的state变量,而你只需保证在组件的顶层(不在if或任何其他块中)调用它就ok了。

2.使用生命周期函数

在类组件中,您拥有componentDidMount,componentWillUnmount和componentDidUpdate等生命周期函数,这些函数提供了从变量初始化到API调用等等的用例。
在函数式组件中,Hooks提供useEffect()API,它接受函数作为它的参数,在首次渲染组件时运行,在后面每次重新渲染或组件更新时也会运行。React首先会更新DOM,然后调用传递给useEffect()的函数,与旧的componentDidMount和componentDidUpdate有点类似,但是又有所不同,因为这些操作都不会阻止UI渲染,即使是阻塞了代码,这使我们的APP感觉上更快了。

import React,{ useEffect, useState }from 'react'

const CounterWithNameAndSideEffect = () => {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('Flavio')

  useEffect(() => {
    console.log(`Hi ${name} you clicked ${count} times`)
  })

  return (
    <div>
      <p>
        Hi {name} you clicked {count} times
      </p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <button onClick={() => setName(name === 'Flavio' ? 'Roger' : 'Flavio')}>
        Change name
      </button>
    </div>
  )
}

ReactDOM.render(
  <CounterWithNameAndSideEffect />,
  document.getElementById('app')
)

如果我们使用useEffect()有点类似于componentWillUnmount的功能应该怎么操作呢?我们可以在传递给useEffect()的函数里再返回一个函数:

useEffect(() => {
  console.log(`Hi ${name} you clicked ${count} times`)
  return () => {
    console.log(`Unmounted`)
  }
})

在每次重新渲染/更新时,useEffect()函数都会执行,这时我们可以给useEffect添加第二个参数来告诉React跳过运行,这个参数是一个包含了需要监视的state变量的数组,如果数组中的其中一项发生改变,react将只会重新执行useEffect:

useEffect(
  () => {
    console.log(`Hi ${name} you clicked ${count} times`)
  },
  [name, count]
)

有点类似的是,你也可以传递一个空数组,这样的话,React只执行一次useEffect(在挂载时):

useEffect(() => {
  console.log(`Component mounted`)
}, [])

3. Hooks规则

以上是Hooks的最基本的用法,理解这些,基本能应付大部分的应用场景,在react官方文档中,定义了Hooks的两条规则:

  • 在最顶层调用Hooks
    不要在循环,条件或嵌套函数中调用Hook。 相反,始终在React函数的顶层使用Hooks。 通过遵循此规则,您可以确保每次组件呈现时都以相同的顺序调用Hook。 这就是允许React在多个useState和useEffect调用之间正确保留Hook状态的原因。
  • 只在react 函数式组件中调用Hooks
    不要在普通js函数中调用Hooks,你只能在react函数式组件中调用Hooks或者在普通的Hooks中调用Hooks。

更多详情可以参考Hooks的官方文档

持续更新中

上一篇:React快速上手5-react中的事件和生命周期函数

相关文章

网友评论

      本文标题:React快速上手6-Context、高阶组件和Hooks

      本文链接:https://www.haomeiwen.com/subject/ypkvmqtx.html