【系列化】reactJS项目构建2--react基础
发布在reactJS2017年11月16日view:235React
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

React 基础知识

如果队React基础不太清晰的可以访问慕课网学习:React入门基础


hello world

import React from 'react'
import { render } from 'react-dom'

// 定义组件
class Hello extends React.Component {
   render() {
       // return 里写jsx语法
       const arr = ['a', 'b', 'c']
       return (
         <div>
           {/* jsx 里的代码注释 */}
           <p 
             onClick={this.clickHandler.bind(this)} 
             className="title"
             style={{ display: true ? 'block' : 'inline', fontSize: '20px' }}
           >
             hello world
           </p>

           <ul>
             {
               arr.map((key, index) => {
                 return <li key={index}>this is {key}</li>
               })
             }
           </ul>
         </div>
       )
   }
   clickHandler(e){
       // e 即js中的事件对象,例如 e.preventDefault() 
       // 函数执行时 this 即组件本身,因为上面的 .bind(this) 
       console.log(Date.now());
   }
}
// 渲染组件到页面
render(
   <Hello/>,
   document.getElementById('root')
)
* import React from ‘react’ 引用的是什么?

这里的 ‘react’ 对应的就是 ./package.json 文件中 dependences 中的 ‘react’。

* 关于bind(this)

如果没有bind(this)的话,只要不掉用Hello组件里的其他函数,也是没有问题的,但是如果想要在clickHandler函数中调用Hello组件里的其他函数,那么this的绑定是很重要的。

* 关于{}

在jsx里{}里是写入js规则代码的标示符。比如style中,为什么会是两个{}呢?那我们把里面的值拿出来,在jsx外(即return外)命名一个变量

const obj = {
  display: ture ? 'block' : 'inlline',
  fontSize: '20px'
}

可以看出来,变量 obj 其实就是个 js 规则里的一个对象变量。然后再把这个变量放入 jsx 里的 style 属性。

之前说了,在 jsx 里,{} 是放入 js 代码的,所以 ‘hello world’ 那里应该是 style = {obj} ,所以就不奇怪,为什么 style 那里有两个{}。


代码分离

enter image description here

项目的初步文件流如上图,我们一个一个倒序解释

* index.tmpl.html

初步了解React后知道,react需要一个HTML页面来注入JSX转换后的DOM结构,所以index.tmpl.html就是这个容器:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    <title>React demo</title>
  </head>
  <body>
    <div id='root'>
    </div>
  </body>
</html>
* index.jsx

这个jsx文件,是整个项目的入口文件,不管内部组件和组件有怎么复杂的业务逻辑,最后都要通过这个文件render出来,然后注入到html容器里:

import React from 'react'
import { render } from 'react-dom'

import Hello from './containers/Hello/';

render(
    <Hello/>,
    document.getElementById('root')
)
* container文件夹

container文件下,是以页面为单位的组件。

container下的Hello文件夹即为:项目中有一个名为Hello的页面。

我们看到的Hello文件夹下的subpage中的文件是组成Hello页面里的各个部分:轮播、列表、推荐。

Hello文件下的index.jsx就是Hello页面的入口文件,其代码如下:

import React from 'react'

import Header from '../../components/Header'
import Carousel from './subpage/Carousel'
import Recommend from './subpage/Recommend'
import List from './subpage/List'

export default class Hello extends React.Component {
    render() {
        return (
            <div>
                <Header title="hello页面"/>
                <Carousel/>
                <Recommend/>
                <List/>
            </div>
        )
    }
}
* components文件夹

以上介绍的是页面和复杂页面的拆分,但那都是页面层级的,即page层。这里复杂页面拆分为subpage其实没什么特别的,就是把复杂页面的代码拆分一下,会更加符合开放封闭原则。

而且,只有复杂页面才有必要去拆分,简单页面根本没必要拆分。因此,无论是page还是subpage它都是页面级别的。

页面的特点是其独特性,一个页面就需要创建一个文件(如果两个页面可以共用一个文件,这是设计不合理,得治!)。

而页面其中的内容,就不一定是这样子了。例如,现在的APP每个页面最上面都会有个 header。每个页面都有,样子差不多,难道我们要为每个页面都做一个?——当然不是。

所以有了components文件,这个文件存放的就是各个页面都可能用到的组件,比如上面我们说的Header组件。


数据传递 & 数据变化

* props

这个需要接着Header的话题接着往下说,每个页面都会使用Header,而每个页面的Header上显示的标题又不一样。所以我们需要这样解决:以Hello 页面为例,页面Hello引用Header后,需要设置一个title属性

<Header title="hello页面"/>

而在Header组件中可以这样取到

import React from 'react'

export default class Header extends React.Component {
    render() {
        return (
             <p>{this.props.title}</p>
        )
    }
}

在 React 中,父组件给子组件传递数据时,就是以上方式,通过给子组件设置 props 的方式,子组件取得 props 中的值即可完成数据传递。

被传递数据的格式可以是任何 js 可识别的数据结构,上面demo是一个字符串。React 中,props 一般只作为父组件给子组件传递数据用,不要试图去修改自己的 props ,除非你想自找麻烦.

* state

上面提到了 props 不能被自身修改,如果组件内部自身的属性发生变化,该怎么办?—— React 为我们提供给了 state,先看一个demo:

export default class Hello extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            // 显示当前时间
            now: Date.now()
        }
    }
    render() {
        return (
            <div>
                <p onClick={this.clickHandler.bind(this)}>hello world {this.state.now}</p>
            </div>
        )
    }
    clickHandler() {
        // 设置 state 的值的时候,一定要用 this.setState ,不能直接赋值修改
        this.setState({
            now: Date.now()
        })
    }
}

React 会实时监听每个组件的 props 和 state 的值,一旦有变化,会立刻更新组件,将结果重新渲染到页面上。


智能组件 & 木偶组件

这是用 React 做系统设计时的两个非常重要的概念。虽然在 React 中,所有的单位都叫做“组件”,但是通过以上例子,我们还是将它们分别放在了 ./app/containers./app/components 两个文件夹中。为何要分开呢?

  • 智能组件 在日常开发中,我们也简称“页面”。为何说它“智能”,因为它只会做一些很聪明的事儿,脏活累活都不干。它只对数据负责,只需要获取了数据、定义好数据操作的相关函数,然后将这些数据、函数直接传递给具体实现的组件即可。./app/containers

  • 木偶组件 这里“木偶”一词用的特别形象,它总是被人拿线牵着。它从智能组件(或页面)那里接受到数据、函数,然后就开始做一些展示工作,它的工作就是把拿到的数据展示给用户,函数操作开放给用户。至于数据内容是什么,函数操作是什么,它不关心。./app/components


生命周期

React详细可参照 React组件生命周期 。在这先简单介绍几个常用的几个生命周期函数(hook)。

* getInitialState

初始化组件 state 数据,但是在 es6 的语法中,我们可以使用以下书写方式代替

class Hello extends React.Component {
    constructor(props, context) {
        super(props, context);
        // 初始化组件 state 数据
        this.state = {
            now: Date.now()
        }
    }
}
* render

最常用的hook,返回组件要渲染的模板。

* componentDidMount

组件第一次加载时渲染完成的事件,一般在此获取网络数据。实际开始项目开发时,会经常用到。

* shouldComponentUpdate

主要用于性能优化,React 的性能优化也是一个很重要的话题,会和router一起记录讲解。

* componentDidUpdate

组件更新了之后触发的事件,一般用于清空并更新数据。实际开始项目开发时,会经常用到。

* componentWillUnmount

组件在销毁之前触发的事件,一般用户存储一些特殊信息,以及清理setTimeout事件等。

评论
发表评论
暂无评论
WRITTEN BY
娜娜娜娜
本人已懒到爆……
TA的新浪微博
PUBLISHED IN
reactJS

我竟然还会这个~

我的收藏