[React] 从零开始的react
组件
1. 无状态组件
- 在React中,组件的名字必须用大写字母开头,而包含该组件定义的文件名也应该是大写字母(便于区分,也可以不是)。
- 无状态组件是纯展示组件,仅仅只是用于数据的展示,只根据传入的props来进行展示,不涉及到state状态处理,通过函数式的方式来创建一个无状态函数式组件(大多数组件都是无状态组件,通过简单的组合可以构建成其他的组件,最后合并成一个大的应用)。
- 无状态函数式组件是一个只带有render方法的组件,通过函数形式或者箭头函数形式创建,该组件无state状态。
import React from "react";
//创建方式一,相当于es5的函数声明的方式创建
function NoState (props) {
return (
<div>this is NoState Component</div>
)
}
//创建方式二,相当于es5的函数表达式的方式创建
const NoState = (props) => {
return (
<div>this is Nostate Component</div>
)
}
export default NoState
- 无状态函数式组件没有组件实例化的过程,成为一个render方法的函数来执行,减少分配的内存,使整体渲染性能得到提高,因此展示数据的组件优先选择这种方式。
- 无状态组件没有实例化得过程,因此无法访问组件this中的对象
- 无状态组件不需要组件生命周期管理和状态管理,底层在实现这种形式的组件的时候不会实现组件的生命周期方法,所以无状态组件不能参与组件生命周期管理
- 无状态组件只能访问传入的props,同样的props会得到同样的渲染结果
当我们的组件开始有逻辑处理,之前的那种方式胜任不了时索要采取的一种形式,通过继承react的Component对象而来
代码的render方法,则是Component中,专门提供的用来处理jsx模板的方法。
第一种方式不同的是,我们接收传入进来的参数,使用的是this.props,第一种方式将props放置于函数参数中,而这种方式则是将props挂载与实例对象上,因此会有所不同
// helloWorld.jsx
import React, {Component} from 'react';
class HelloWorld extends Component {
clickHander = () => {
console.log(this.props);
console.log(this.props.name);
}
render() {
return (
<div onClick={this.clickHander}>{ this.props.name } say: Hello World!</div>
)
}
}
export default HelloWorld;
组件之间的交互
父组件与子组件之间的交互
- 父组件修改子组件,只需要修改传入的props属性
- 子组件修改父组件,需要父组件向子组件传递一个函数,该函数在父组件中定义,在子组件中触发执行
子组件与子组件之间的交互 - 通过影响共同的父组件来进行交互
state = {
switch: 0,
name: this.props.name1
}
clickHander = () => {
const {name1, name2} = this.props;
if (this.state.switch === 0) {
this.setState({
switch: 1,
name: name2
})
} else {
this.setState({
switch: 0,
name: name1
})
}
};
render() {
return (
<div onClick={this.clickHander}>hello world !{this.state.name}</div>
)
}
先来说说state相关的基础知识。首先了解ES6 class语法的同学都应该知道,当我们通过这种方式来写的时候,其实是将state写入了构造函数之中。
state = {} // 等同于ES5构造函数中的this.state = {}
在对象中,我们可以通过this.state的方式来访问state中所存储的属性
setState接收一个对象,它的运行结果类似于执行一次assign方法。会修改传入的属性,而其他的属性则保持不变
react赋予state的特性,则是当state被修改时,会引起组件的一次重新渲染。即render方法会重新执行一次。也正是由于这个特性,因此当我们想要改变界面上的元素内容时,常常只需要改变state中的值就行了
而setState也有一个非常重要的特性,那就是,该方法是异步的。它并不会立即执行,而会在下一轮事件循环中执行
// 假设state.name的初始值为Tom,我们改变它的值this.setState({ name: 'Jason'})// 然后立即查看它的值console.log(this.state.name) // 仍然为Tom,不会立即改变
refs
react组件其实是虚拟DOM,因此通常我们需要通过特殊的方式才能拿到真正的DOM元素。大概说一说虚拟DOM是个什么形式存在的,它其实就是通过js对象的方式将DOM元素相关的都存储其实,比如一个div元素可能会是这样
// 当然可能命名会是其他的,大概表达一个意思,不深究哈
{
nodeName: 'div',
className: 'hello-world',
style: {},
parentNodes: 'root',
childrenNodes: []
...
}
而我们想要拿到真实的DOM元素,react中提供了一种叫做ref的属性来实现这个目的
import React, { Component } from 'react';
class HelloWorld extends Component {
clickHander = () => {
console.log(this.refs)
}
render () {
return (
<div className="container" onClick={this.clickHander}>
<div ref="hello" className="hello">Hello</div>
<div ref="world" className="world">World</div>
</div>
)
}
}
export default HelloWorld;
为了区分ES6语法中的class关键字,当我们在jsx中给元素添加class时,需要使用className来代替
我们在jsx中,可以给元素添加ref属性,而这些拥有ref属性的元素,会统一放在组件对象的refs中,因此,当我们想要访问对应的真实DOM时,则通过this.refs来访问即可。
当然,ref的值不仅仅可以为一个名字,同时还可以为一个回调函数,这个函数会在render渲染时执行,也就是说,每当render函数执行一次,ref的回调函数也会执行一次。
// src/helloWorld.jsx
import React, { Component } from 'react';class HelloWorld extends Component {
clickHander = () => {
console.log(this.refs)
} refCallback = (elem) => {
console.log(elem);
} render () {
return (
<div className="container" onClick={this.clickHander}>
<div ref="hello" className="hello">Hello</div>
<div ref={this.refCallback} className="world">World</div>
</div>
)
}
}export default HelloWorld;
组件生命周期
件的生命周期,指的就是一个组件,从创建到销毁的这样一个过程,react为组件的生命周期提供了很多的钩子函数
react组件有三种状态:
- Mounted:已经插入真实DOM
- Updating:正在被重新渲染
- Unmounted:已移出真实DOM
每个状态的处理函数
- will:函数在进入状态之前调用
- did:函数在进入状态之后调用
组件第一次渲染完成的前后时刻,所谓的渲染完成,即组件已经被渲染成为真实DOM并插入到了html之中
- componentWillMount 在首次渲染完成之前,此时可修改组件的state
- componentDidMount 真实DOM渲染完成之后,该方法可通过this.getDOMNode()访问到真实的DOM元素,可以使用其他的类库来操作这个DOM
组件属性(我们前面提到的props与state)更新的前后时刻
- componentWillUpdate 接收到一个新的state或者props时,在重新render之前调用,此时不允许更新props和state
- componentDidUpdate 组件完成更新之后调用,此时可访问新的DOM元素
组件取消挂载之前(取消之后就没必要提供钩子函数了)
componentWillUnmount
两个特殊的处理函数
componentWillReceiveProps(object nextProps):组件接收到新的props时,在重新render之前调用,此时可以更改props和state。首先props发生改变->然后componentWillReceiveProps去判断是否需要重新渲染(shouldComponentUpdate)->如果不需要则继续running->如果需要则执行componentWillUpdate->渲染DOM树之后执行componentDidUpdate->进入runningshouldComponentUpdate(nextProps, nextState)(更新发生前立即被调用) 接收到一个新的state或者props时,在重新render之前调用,组件判断是否重新render前调用。首先state发生改变->判断是否需要重新渲染新的props和state(shouldComponentUpdate) -> 根据判断决定执行render过程还是继续·保持running状态
三个统一调用的方法,用于组件初始化,获取默认属性和状态
- getDefaultProps:作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享
- getInitialState:作用于组件的实例,在实例创建时只调用一次,,用于初始化没个实例的state,可访问this.props
- render:必选的方法,创建vistual DOM (1. 只能通过this.props和this.state访问数据 2. 可以返回null、false或任何React组件 3. 只能出现一个顶级组件(不能返回数组)4.不能改变组件的状态 5. 不能修改DOM的输出
已挂载的方法
- component.forceUpdate() 可以在任何已经挂载的组件上使用,当你知道某些深处的组件状态未通过this.setState而改变了的时候
componentDidMount,组件第一次渲染完成之后调用的componentDidMount,既然是组件第一次渲染完成之后才会调用,也就是说,该函数在react组件的生命周期中,只会调用一次。而渲染完成,则表示组件已经被渲染成为真实DOM插入了html中。所以这时候就可以通过ref获取真实元素。在实际开发中,常常需要通过ajax获取数据,而数据请求的这个行为,则最适合放在componentDidMount中来执行。通常会在首次渲染改变组件状态(state)的行为,或者称之为有副作用的行为,都建议放在componentDidMount中来执行。主要是因为state的改动会引发组件的重新渲染。
别人的图,忘了哪里的了

PropTypes
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// You can declare that a prop is a specific JS primitive. By default, these
// are all optional.
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,
// A React element.
optionalElement: PropTypes.element,
// You can also declare that a prop is an instance of a class. This uses
// JS's instanceof operator.
optionalMessage: PropTypes.instanceOf(Message),
// You can ensure that your prop is limited to specific values by treating
// it as an enum.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// An object taking on a particular shape
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// You can chain any of the above with `isRequired` to make sure a warning
// is shown if the prop isn't provided.
requiredFunc: PropTypes.func.isRequired,
// A value of any data type
requiredAny: PropTypes.any.isRequired,
// You can also specify a custom validator. It should return an Error
// object if the validation fails. Don't `console.warn` or throw, as this
// won't work inside `oneOfType`.
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// You can also supply a custom validator to `arrayOf` and `objectOf`.
// It should return an Error object if the validation fails. The validator
// will be called for each key in the array or object. The first two
// arguments of the validator are the array or object itself, and the
// current item's key.
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
[React] 从零开始的react的更多相关文章
- 用webpack4从零开始构建react脚手架
用webpack4从零开始构建react脚手架 使用脚手架 git clone git@github.com:xiehaitao0229/react-wepack4-xht.git` `cd reac ...
- react起步——从零开始编写react项目
# index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...
- React 引入import React 原理
本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖. 所以我们如果使用了JSX,我们其实就是在使用React,所以我们就 ...
- [react] 细数 React 的原罪
Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...
- React Native & react-native-web-player & React Native for Web
React Native & react-native-web-player & React Native for Web https://github.com/dabbott/rea ...
- React笔记:React基础(2)
1. JSX JSX是一种拥有描述UI的JavaScript扩展语法,React使用这种语法描述组件的UI. 1.1 基本语法 JSX可以嵌套多个HTML标签,可以使用大部分符号HTML规范的属性. ...
- React 学习(一) ---- React Element /组件/JSX
学习React的时候,你可能听到最多的就是要先学习webpack, babel,要先学会配置然后才能学react 等等,一堆的配置就把我们吓着了,根本就没有心情就学习react了.其实在最开始学习re ...
- React.createClass 、React.createElement、Component
react里面有几个需要区别开的函数 React.createClass .React.createElement.Component 首选看一下在浏览器的下面写法: <div id=" ...
- 【React】初识React
React是什么 React是如今(2015年)最热门的前端技术. 在React中.一切皆组件. A JavaScript library for building user interfaces R ...
随机推荐
- ChartControl设置坐标轴范围
需求:有一条坐标轴是用来表示百分比的,所以刻度范围只能是从0 - 100: 解决方法:运行chatcontrol设计器,选中需要设置的轴,如下图: 设置Whole range 的最大最小值: 默认情况 ...
- boa调试
Cannot access memory at address 0x0 0x400fc7e0 in ?? () 0 0x4014f0dc in wcscasecmp_l () from /lib/li ...
- C#等同于正则表达式的写法
不用写正则表达式,用C#自带的方法 用char 自带的函数实现 /// <summary> /// 只能由数字和大小写字母组成 /// </summary> /// <p ...
- Shadow Copying导致ASP.NET应用启动很慢的解决办法
What's Shadow Copying? 我们安装一个应用程序并启动后,我们是无法更新应用程序安装目录中程序集文件的.如果强制替换会提示文件正在使用,如下图所示. 那你可能会问,为什么会无法更新呢 ...
- 【安富莱专题教程第1期】基于STM32的硬件RGB888接口实现emWin的快速刷新方案,32位色或24
说明:1. 首先感谢ST终于推出了ARGB格式的emWin库,可谓千呼万唤始出来,使用STM32的硬件RGB888接口刷新图片慢的问题终于得到解决.2. 这个问题由来已久,是之前为我们的STM32-V ...
- #Java学习之路——基础阶段(第七篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- [Swift]LeetCode72. 编辑距离 | Edit Distance
Given two words word1 and word2, find the minimum number of operations required to convert word1 to ...
- [Swift]LeetCode773. 滑动谜题 | Sliding Puzzle
On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty square repre ...
- [Swift]LeetCode778. 水位上升的泳池中游泳 | Swim in Rising Water
On an N x N grid, each square grid[i][j]represents the elevation at that point (i,j). Now rain start ...
- 通信统计接口字段填充内容shell脚本
现在通信行业上班,最麻烦的就是计算各个协议接口字段填充的内容是否正确.经历了小白似的一个个字段统计在到单个接口所有字段统计,然后到现在的多个接口一次统计.在大大节省了时间的同时,让自己有更充足的时间来 ...