React入门

584 阅读5分钟

本文适合未实操过react项目,想要学习react看过一遍官网的react新手,可以借此文章更通畅地结合官网学习。笔者写Vue,因此有一些用法会和vue对比说明一下。关于react的理解还不透彻,如有不当请不吝指正。

一、基础部分

  • JSX
JSX是javascript的语法扩展。react中不强制要求使用JSX,但是在react中使用JSX能够更清晰地发现渲染逻辑和UI逻辑之间的关联。

举个栗子:

const a = <a href="https://www.baidu.com" >百度一下,你就知道</a>

以上JSX语法会被插件转换成

`const a =React.createElement('a', {href: 'https://www.baidu.com'}, '百度一下,你就知道')`

再由react转化成正真的DOM树

  1. JSX嵌入表达式,用 {} 包裹

    const name = 'Kathie Yu'; const el =

    Hello, { name }

    2. js逻辑插入JSX

【注意】:JSX语法需要用小括号来做标识,单行可省略;JSX中类名等属性、绑定事件采用驼峰命名如className、onClick;组件名以大写字母开头,区分html标签。
  • state
state是react组件中的状态,相当于Vue中的data用法。与Vue不同的是他不能直接通过=赋值,因为vue底层通过Object.defineProperty给data中声明的变量都进行了getter和setter的处理,是的视图层能够时时更新,而react中没有,所以就必须要使用react自己的方法setState来更新。
state使用:

1. 类组件中在constructor内初始化 

2. 使用setState方法更新

【注意】setState有两种写法:

setState({count: this.state.count +1}) 和 setState((prevState, props) => ({count: prevState.count +1 }))

后者可以处理异步更新state
需要异步处理的原因:在多次使用this.setState({})更新state时,react内部实际上采用的是对象合并,相当于Object.assign方法,因此后面的操作会覆盖之前的;但是换成异步函数的话,react的处理机制就不一样了,他会将传入的更新state的函数放到一个队列,然后按照顺序依次调用。

或许我们来看一个例子会更清晰:

以上组件在回调中希望执行两次setState,但实际结果是count只加了1,这种情况下应该要使用异步处理的方法。

  • 事件处理

【注意】在类组件中,为了在回调函数中使用this,必须要在constructor中绑定,或者使用箭头函数调用
  • 条件渲染
JSX中在{ }中可以进行逻辑运算。常常使用三目运算、条件与(&&)。如果需要阻止渲染,直接让render方法返回null。
  • 列表渲染

【注意】:便利时必须要给列表加上key属性,原理同VUE
  • 表单

【注意】react中表单没有双向绑定的概念,需要在change事件中通过setState重新赋值,这样模拟vue中的双向绑定;
  • 组件和props
  1. 组件类型:类组件和简单组件
  2. 类组件使用es6中的class定义
  3. 简单组件就是函数组件(在16.8之前他是无状态组件)
  4. 组件的生命周期
      a. 挂载
         constructor(props) ==>组件初始化,初始化state,为事件处理函数绑定实例
         render() ==>class组件中必须实现的方法
         componentDidMount() ==>组件挂载后立即调用,依赖dom节点的初始化应放在这             里。
     b. 更新
         shouldComponentUpdate(nextProps, nextState) ==> 当props和state发生变化                 时,此方法会在渲染执行之前被调用,返回值默认为true。首次渲染或使用                            forceUpdate()时不会调用该方法。
        render()
        getSnapshotBeforeUpdate(prevProps, prevState) ==> 最近一次渲染输出之前调                用。可以在组件发生改变之前从DOM捕获一些信息(例如滚动位置)。此方法的任何              返回值将作为参数传递给componentDidUpdate(preProps, prevState, snapshot)
        componentDidUpdate() ==>组件更新后会被立即调用。首次渲染不会执行此方法。
    c. 卸载
        componnentWillUnmount() ==>组件卸载及销毁前直接调用。可在此方法中执行必要          清理,如清除timer或订阅

  3. props的使用

【注意】:react的数据流是自上而下通过props传递,react不允许在组件内部修改props;如果需要在子组件中修改父组件中的state,则需要通过props传入一个更新state的方法给子组件来调用。这点Vue是通过$emit方法来触发更新的

二、高阶部分(context,refs,render props,高阶组件,hook)

  • context
context的设计是为了解决react中有一些类似“全局”的数据传输问题,因为react数据是自上而下传递的,如果不用context时是通过父子组件的props来显示传递,为了解决这种冗余可以使用context。当然也可以使用redux等仓库,但实际上这些仓库也是通过context来实现的。
context的使用:
使用前通过props显示传递:

使用context后:

【注意】一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据
  • refs&DOM
1\. 通过`this.myRef = React.createRef()`创建ref绑定到组件实例,并通过ref属性附加到react元素上

访问时,在ref的current属性中取出 const node = this.myRef.current

【备注】在16.3之前使用回调refs,通过ref传递一个函数,函数接受组件实例或DOM元素作为参数,以使他们能在其他地方被访问或储存;以上方法只支持在类组件中使用ref,不支持在函数组件中使用,因为函数组件没有实例。如果在函数组件中使用ref,需要使用forwardRef并了解一下refs转发

2.refs转发

ref操纵dom的做法其实和vue中的ref并没有什么太大区别,但是react中的ref支持操纵子组件中的元素(透传),这个是vue中没有的用法,就是refs的转发功能
forwardRef()方法包裹在子组件外层,接收一个函数,第一个参数是props第二个是ref,函数返回子组件的JSX,这时可以将ref指向任何你想要的元素,并在父组件中拿到它

【注意】refs在componentDidMount生命周期之后才能拿到;ref不是prop属性,不能通过this.props.ref取出

3. Render Props和高阶组件

首先要理解他们的出现都是为了复用公共逻辑。
1\. react中render props这种技术可以对照vue中作用域插槽理解。具有render prop的组件接受一个函数(react中万物都可以通过props传递下去),该函数返回一个React元素并使用组件中传入的参数渲染UI。
举个栗子:
这是一个跟踪页面上鼠标位置的组件,当前在鼠标位置显示一个粉色圆![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/341a93108da84d22bbb2985bfcd1c795~tplv-k3u1fbpfcp-zoom-1.image)

但是,如果我不希望它总是显示圆,我希望它可以显示自定义的UI,可能是图片或其他一个组件,这样就需要把获取鼠标位置这个功能封装。

render props的实现方式如下:

使用:

使用时有两种方法:1、通过props传递一个函数返回react元素,当然这个prop名字不一定非要叫render可以自定义;2、在组件闭合标签中传入函数,用props中固定的children属性调用,这种用法和vue中的作用域插槽就很像了

2. 高阶组件(HOC)

HOC是react中用于复用组件逻辑的一种高级技巧,简单点来说HOC是一个函数,接受一个组件作为参数,添加一些新的功能(不进行UI改造),再返回一个组件。一般用于提取不同类别组件中的相似行为。
还是同一个栗子,我们用HOC进行改造

希望为另外的组件添加MouseHOC的功能,我们这样使用

【注意】HOC不应该修改传入的组件,但可以使用组合的形式;HOC可以同时接收多个参数;常见的HOC签名,例如redux的connect函数 

const ConnectedComment = connect(commentSelector, commentActions)(CommentList);

3. 二者差异化理解

render props更像是vue中的作用域插槽;而HOC则是mixin用法的优化
最明显的区别是前者对组件进行改动,渲染发生了改变,后者组件发生未改动,原组件渲染未改变,但允许组合;
控制权上有一定的区别,前者控制权在子组件上,也就是函数返回的react元素,后者控制权在wrapper组件,最后的渲染结果由父组件决定;二者功能实现上大体相似
  • Hook
他是react V16.8的新特性,是一种与class并行的状态管理方法,是不影响之前的组件并向后兼容的
出现的原因:hook使你在无需修改组件结构的情况下复用状态逻辑(简单上说,上述的render props和高阶组件)
【注意】hook只能在函数组件中使用
  1. State Hook
      之前我们提到组件的两种形式:类组件和函数组件;在认识hook之前,函数组件是无状            态的,只能接收props并渲染,但现在它具有了和class同样的状态管理能力

      a. useState()方法==class中this.state

      b. useState参数是当前声明的state的初始值,他不必须是对象形式,可以是任何你想要的的数据格式

      c. useSate方法返回state和修改state的方法,这个方法==this.setState()

2. Effect Hook

函数组件中同样也是没有生命周期的,useEffect hook就实现类似componentDidMount和componentDidUpdate生命周期的功能
  1. useEffect()在组件渲染(包括组件第一次渲染)后执行,这会让我们减少一些重复代码(例如同时需要在componentDidMount和componentDidUpdate中执行操作时)
  2. 在一些需要清除的effect中,hook支持在同一个useEffect中做清除操作,写法如下(组件销毁时执行return后的函数)

    3. hook实现的性能优化。到这里我们知道每个effect中都执行特定逻辑,每次渲染更新都           会清除之前的effect并生成新的effect,但是不是每一个effect都需要重新执行,这种情             况下应该跳过来进行性能优化,effect hook支持特定值调用effect,只要传递数组作为             第二个可选参数即可

useEffect(()=>{documen.title = `You clicked ${ count } times!`}, [count])
      如果只希望执行一次effect(仅在组件挂载和卸载时执行),可以传递一个空数组( [] )

3. Hook使用规则

Hook需要在函数组件的最顶层调用,不要在条件或循环中调用

4. 自定义Hook

在提取组件中共享逻辑时会需要用到自定义hook。他是一个以“use”开头的函数,可以自由地决定他的参数是什么,以及他应该返回什么
还是同一个栗子,使用hook进行改造:

5. 总结

a. 使用hook后再也不用管this指向的问题了
b.不用陷入高阶组件和render props层层嵌套的复杂逻辑中
c.hook中关联逻辑或功能都在一块,不写重复代码,新手维护也简单了不止一倍
d.上面介绍的只是常用的两种hook,当然hook的功能远不止这些

本文仅仅是react入门,所说明的内容也并非完全,需要更细致地学通react的同学我们还是再多看几遍官方文档+实操吧,实践出真知哦~~