React 组件浅析

React 组件

React书写的一切用户界面都是基于组件的,将界面分割成一些独立的,可复用的部件.

一.声明组件

1.ES5写法:React.createClass()

最老版本的用法,不建议使用,已经废弃了

实际上,createClass() 本质是一个工厂函数

虽然这种方法已经废弃了,但是Facebook出了一个能代替React.createClass() 的替代品,需要使用create-react-class模块,先安装

$ npm install create-react-class -S
import React from 'react';
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
    render: function () {
        return <h1>使用create-react-class模块创建react组件</h1>;
    }
});

export default Greeting;

2.ES6写法:React.Component

目前官方极为推荐的创建有状态组件的方式

支持 class语法 (状态 属性 生命周期) [email protected] =>class生命周期写法升级

import React from 'react';
import ReactDOM from 'react-dom';

class Animal extends React.Component {
   render() {
       return (
           <div>Animal组件</div>
       )
   }
}

ReactDOM.render(
   <div>
       <Animal></Animal>
   </div>,
   document.getElementById('root')
);

类定义的组件

  • 定义一个类,类名就是组件名
  • 这个类需要继承React.Component基础组件
  • 类中的render函数是必须的,render函数中的return出来的是一段JSX语法,这一段JSX语法就是这个组件的模版的内容

3.函数式组件

无状态函数式写法

不支持状态 属性 生命周期

[email protected] => 支持状态 属性 “生命周期” React Hooks

import React from 'react';
import ReactDOM from 'react-dom';

const Cat = () => {
    return (
        <div>
            Cat组件
        </div>
    );
}

ReactDOM.render(
    <div>
        <Cat></Cat>
    </div>,
    document.getElementById('root')
);

函数式的定义组件

  • 定义一个函数,然后return出来一段JSX语法,这一段JSX语法就是这个组件的模版的内容
  • 函数名称就是组件的名字,[所以首字母需要大写()

PS:组件模版内容,如果需要换行的话,return后面需要写小括号()括起来,因为原生js,是会返回undefind

2.模版内容只能有一个跟元素

二.组件注意事项

1.组件名首字母大写

组件名,在被引用时 首字母必须大写 编译时会被认为是自定义组件,如果写成了小写,会被认为是原生js的dom节点

2.一个根元素

组件的最外层必须有一个标签包裹,不能有兄弟元素

3.return需要加上小括号

return加上小括号,可以回车,如果内容多了,肯定不会写成一行,原生中return后面没有跟内容,会返回undefind

4.组件是可以嵌套的

组件是可以嵌套的,如父子组件

三.状态(state)

每个React组件都有自己的状态(除了函数式组件外),state只存在于组件自身内部,用来存储自身的数据,相当于Vue中的data选项

1.定义state

在组件内部的构造器中,直接定义this.state

constructor(props) {
    super(props);
    this.state = {
        data: {
            name: 'liuqiao',
            age: 18
        }
    };
}

在ES7中可以直接省略构造器,直接在当前Class中定义也可以,但是为了规范,建议还是不要省略

 // 注意,这里是es7的写法
 //不是状态,单纯只是变量
 a=10;
 //状态
 state = {
     name: 'liuqiao',
     age: 18
 }

2.访问state

同样,在需要使用当前状态的地方,通过this.state访问状态

render() {
    return (
        <div>
            我的名字叫{this.state.data.name}
        </div>
    );
}

3.改变state

改变state时,使用React内置的setState()方法修改state,每当使用setState时,React会将需要更新的state合并后放入状态队列,触发调和过程,而不是立即更新state.所以,setState是异步的

this.setState({
    username:'xiaohong'
});

在需要修改的地方触发此方法即可!另外,如果要修改setState里面的对象的某一属性,但不会修改其他的属性呢?

this.state = {
    username:'xiaoming',
    data: {
        name: 'liuqiao',
        age: 18,
        address:'深圳',
        like:['爬山','跑步']
    }
};

比如我要当前状态中的data对象中的name属性,但是其他属性不修改,我不可能,为了修改一个name属性,把其他的都在setState里都带上吧,那样肯定是不行的,所以我提供了如下方法:

1.方法一
let newData = { ...this.state.data };
newData.name=30;
this.setState({
    data: newData
});

采用展开运算符,全部展开,然后只赋值需要修改的属性即可.其实原理呢,就是将原来的对象浅拷贝一个新对象,然后新对象改变属性之后,再浅拷贝回来

2.方法二
let newData = Object.assign(this.state.data, {
    ['age']: 30
});
this.setState({
    data: newData
});

采用Object.assign方法功能,其原理就是此方法的特性可以合并具有相同属性的对象

3.方法三
let data=this.state.data;
data.age=30;
this.setState({
    data
});

4.多个改变satae操作情况

culeCount = () => {
    this.setState({
        count: this.state.count + 1
    });
    this.setState({
        count: this.state.count + 1
    });
    this.setState({
        count: this.state.count + 10
    });
    // 这里多个setState操作,会被合并,只会执行最后一次的setState,进行了批量更新优化
}

如果遇到某个函数内进行了多个setSatae的情况,会被合并,整合上面的setState,如果有重复的,只会执行最后一次的setState,进行了批量更新优化

5.setState异步

setState()方法接收2个参数,后面参数可以选

this.setState({
    myname: 'xiaoming'
}, () => {
    //2.再打印
    console.log("我是异步的" + this.state.myname);
    // 
});
//1.先打印
console.log(this.state.myname);

原理:状态更新是异步的,这里的回调函数,会等待状态更新完,并且dom更新完之后,才会被调用,原因是创建虚拟dom,diff算法对比旧的dom节点,和文档碎片,进行最小化重新渲染

6.setState同步

setState在ajax,原生事件,setTimeout是同步的


handleClick2 = () => {
    setTimeout(() => {
        this.setState({
            myname: 'xiaohong'
        });
        console.log(this.state.myname);
        this.setState({
            myname: 'xiaofang'
        });
        console.log(this.state.myname);
    }, 0);
}

官网的一句话:setState 并不保证是同步的!所以,得出结论:setState是否同步异步,是得看情况的,当setState在ajax,原生事件,setTimeout是同步的,其他情况是异步的

四.事件绑定

1.匿名箭头函数写法

比较简洁,适合处理代码少,简洁的逻辑

<button onClick={() => {
    console.log(this.refs.username.value)
}}>提交(匿名箭头函数写法)</button>

2.自定义函数写法

会存在this指向问题,需要使用bind强制改变this指向 注意,必须使用bind才可以,call和 apply不行

原因是call和apply改变this指向后,会立即执行函数

<button onClick={this.submitLogin.bind(this)}>提交(自定义函数写法)</button>

submitLogin(e) {
    //e是事件源
    console.log('自定义函数写法',e);
}

3.自定义声明式箭头函数写法

一般推荐这种方式

<button onClick={this.submitOK}>提交(自定义声明式箭头函数写法)</button>

submitOK=()=>{
    console.log('外部自定义函数', this.refs.username.value);
}

4.改编第一种写法,推崇这种

原理是使用箭头函数做中转,就不会有this指向问题了

<button onClick={(e)=>this.submitLogin('liuqiao','123')}>改编第一种  箭头函数做中转</button>

submitLogin(username,pwd,e) {
    //e是事件源
    console.log('外部自定义函数', username,pwd,e);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章