react.js 小书 学习笔记(二)

作者:胡子大哈
原文链接: http://huziketang.com/books/react/lesson1

看了 react.js 小书 第二阶段的内容,边看边做一点记录,整理了一些知识点。仅供学习。

17.前端应用状态管理 —— 状态提升

当某个状态被多个组件依赖或者影响的时候,就把该状态提升到这些组件的最近公共父组件中去管理,用 props 传递数据或者函数来管理这种依赖或者影响的行为。

如何更好的管理这种被多个组件所依赖或影响的状态?

你可以看到 React.js 并没有提供好的解决方案来管理这种组件之间的共享状态。在实际项目当中状态提升并不是一个好的解决方案,所以我们后续会引入Redux这样的状态管理工具来帮助我们来管理这种共享状态,但是在讲解到 Redux 之前,我们暂时采取状态提升的方式来进行管理。

18.挂载阶段的组件生命周期(一)

我们把 React.js 将组件渲染,并且构造 DOM 元素然后塞入页面的过程称为组件的挂载

你可以理解一个组件的方法调用是这么一个过程:

-> constructor()
-> componentWillMount()
-> render()
// 然后构造 DOM 元素插入页面
-> componentDidMount()
// ...
// 即将从页面中删除
-> componentWillUnmount()
// 从页面中删除

componentWillMountcomponentDidMount都是可以像 render 方法一样自定义在组件的内部。挂载的时候,React.js 会在组件的 render 之前调用 componentWillMount,在 DOM 元素塞入页面以后调用 componentDidMount。

总结:
componentWillMount:组件挂载开始之前,也就是在组件调用 render 方法之前调用。
componentDidMount:组件挂载完成以后,也就是 DOM 元素已经插入页面后调用。
componentWillUnmount:组件对应的 DOM 元素从页面中删除之前调用。

19.挂载阶段的组件生命周期(二)

我们一般会把组件的 state 的初始化工作放在 constructor 里面去做;在 componentWillMount 进行组件的启动工作,例如 Ajax 数据拉取、定时器的启动;组件从页面上销毁的时候,有时候需要一些数据的清理,例如定时器的清理,就会放在 componentWillUnmount 里面去做。

说一下本节没有提到的 componentDidMount 。一般来说,有些组件的启动工作是依赖 DOM 的,例如动画的启动,而 componentWillMount 的时候组件还没挂载完成,所以没法进行这些启动工作,这时候就可以把这些操作放在 componentDidMount 当中。componentDidMount 的具体使用我们会在接下来的章节当中结合 DOM 来讲。

20.更新阶段的组件生命周期

组件的挂载指的是将组件渲染并且构造 DOM 元素然后插入页面的过程。这是一个从无到有的过程

除了挂载阶段,还有一种“更新阶段”。说白了就是 setState 导致 React.js 重新渲染组件并且把组件的变化应用到 DOM 元素上的过程,这是一个组件的变化过程

关于更新阶段的组件生命周期:
shouldComponentUpdate(nextProps, nextState):你可以通过这个方法控制组件是否重新渲染。如果返回 false 组件就不会重新渲染。这个生命周期在 React.js 性能优化上非常有用。

componentWillReceiveProps(nextProps):组件从父组件接收到新的 props 之前调用。

componentWillUpdate():组件开始重新渲染之前调用。

componentDidUpdate():组件重新渲染并且把更改变更到真实的 DOM 以后调用。

21.ref 和 React.js 中的 DOM 操作

React.js 重新渲染的机制帮助我们免除了绝大部分的 DOM 更新操作,也让类似于 jQuery 这种以封装 DOM 操作为主的第三方的库从我们的开发工具链中删除。

但是 React.js 并不能完全满足所有 DOM 操作需求,有些时候我们还是需要和 DOM 打交道。比如说你想进入页面以后自动 focus 到某个输入框,你需要调用 input.focus() 的 DOM API,比如说你想动态获取某个 DOM 元素的尺寸来做后续的动画,等等。

React.js 当中提供了 ref 属性来帮助我们获取已经挂载的元素的 DOM 节点,你可以给某个 JSX 元素加上 ref属性。

class AutoFocusInput extends Component {
  componentDidMount () {
    this.input.focus()
  }

  render () {
    return (
       this.input = input} />
    )
  }
}

ReactDOM.render(
  ,
  document.getElementById('root')
)

我们给 input 元素加了一个 ref 属性,这个属性值是一个函数。

当 input 元素在页面上挂载完成以后,React.js 就会调用这个函数,并且把这个挂载以后的 DOM 节点传给这个函数。

在函数中我们把这个 DOM 元素设置为组件实例的一个属性,这样以后我们就可以通过 this.input 获取到这个 DOM 元素。

然后我们就可以在 componentDidMount 中使用这个 DOM 元素,并且调用 this.input.focus() 的 DOM API。整体就达到了页面加载完成就自动 focus 到输入框的功能。

22.props.children 和容器类组件

使用自定义组件的时候,可以在其中嵌套 JSX 结构。嵌套的结构在组件内部都可以通过props.children获取到,这种组件编写方式在编写容器类型的组件当中非常有用。而在实际的 React.js 项目当中,我们几乎每天都需要用这种方式来编写组件。

23.dangerouslySetHTML 和 style 属性

React.js 中的元素的 style 属性的用法和 DOM 里面的 style 不大一样,普通的 HTML 中的:

React.js 小书

在 React.js 中你需要把 CSS 属性变成一个对象再传给元素:

React.js 小书

style 接受一个对象,这个对象里面是这个元素的 CSS 属性键值对,原来 CSS 属性中带 - 的元素都必须要去掉 - 换成驼峰命名,如 font-size 换成 fontSize,text-align 换成 textAlign。

24.PropTypes 和组件参数验证

都说 JavaScript 是一门灵活的语言,灵活性体现在弱类型、高阶函数等语言特性上。而语言的弱类型一般来说确实让我们写代码很爽,但是也很容易出 bug。

大型应用程序的构建其实更适合用强类型的语言来构建,它有更多的规则,可以帮助我们在编写代码阶段、编译阶段规避掉很多问题,让我们的应用程序更加的安全。

JavaScript 因为它的弱类型,常常意味着不是很安全。所以近年来出现了类似 TypeScript 和 Flow 等技术,来弥补 JavaScript 这方面的缺陷。

React.js 就提供了一种机制,让你可以给组件的配置参数加上类型验证。

我们这里先安装一个 React 提供的第三方库 prop-types:

npm install --save prop-types

导入import PropTypes from 'prop-types'

static propTypes = {
  comment: PropTypes.object
}

我们可以通过 isRequired 关键字来强制组件某个参数必须传入:

...
static propTypes = {
  comment: PropTypes.object.isRequired
}
...

React.js 提供的 PropTypes 提供了一系列的数据类型可以用来配置组件的参数:

PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.node
PropTypes.element
...

25.实战分析:评论功能(四)

持久化用户名

用户输入用户名,然后我们把用户名保存到浏览器的 LocalStorage 当中,当页面加载的时候再从 LocalStorage 把之前保存的用户名显示到用户名输入框当中。

...
  componentWillMount () {
    this._loadUsername()
  }

  _loadUsername () {
    const username = localStorage.getItem('username')
    if (username) {
      this.setState({ username })
    }
  }

  _saveUsername (username) {
    localStorage.setItem('username', username)
  }
  
  handleUsernameBlur (event) {
    this._saveUsername(event.target.value)
  }
...

监听用户名输入框失去焦点的事件,就存储用户名。

组件挂载的时候把用户名加载出来。这是一种数据加载操作,不依赖 DOM 操作的组件启动的操作都可以放在 componentWillMount 中进行,加载用户名。

组件的私有方法都用 _ 开头,所有事件监听的方法都用 handle 开头。把事件监听方法传给组件的时候,属性名用 on 开头。

另外,组件的内容编写顺序如下:

  1. static 开头的类属性,如 defaultProps、propTypes。
  2. 构造函数,constructor。
  3. getter/setter。
  4. 组件生命周期。
  5. _ 开头的私有方法。
  6. 事件监听方法,handle*。
  7. render开头的方法,有时候 render() 方法里面的内容会分开到不同函数里面进行,这些函数都以 render 开头。
  8. render() 方法。

26.实战分析:评论功能(五)

持久化评论

对象的存取要解析成JSON字符串

_loadComments () {
  let comments = localStorage.getItem('comments')
  if (comments) {
    comments = JSON.parse(comments)
    this.setState({ comments })
  }
}

_saveComments (comments) {
  localStorage.setItem('comments', JSON.stringify(comments))
}

你可能感兴趣的:(react.js 小书 学习笔记(二))