react

一:为什么要学 react?

1. 原生js的弊端

  1. 原生js操作DOM繁琐、效率低(DOM-API 操作 UI)
  2. 使用js直接操作DOM,浏览器会进行大量的重回重排
  3. 原生js没有组件化编码方案,代码复用率低

2. react的特点

  1. 采用组件化模式、声明式编码,提高开发效率及组件复用率
  2. 在 React Native 中可以使用 React 语法进行移动端开发
  3. 使用虚拟DOM + 优秀的Diff算法,尽量减少与真实DOM的交互

二:虚拟DOM的两种创建方式(jsx / js)

1.使用 jsx

使用 jsx 需要用 babel 进行转译,最后通过 js 的形式输出, 所以 jsx 只是 React.createElement 的语法糖

使用 jsx 的好处:写法方便,类似html结构,并且有嵌套层次

//1. 创建虚拟DOM
const VNode = <h1>你好</h1>

//2. 渲染虚拟DOM到页面
ReactDOM.render(VNode, document.getElementById("app"));

2.使用 js

React.createElement(标签名, 属性, 内容)

//1. 创建虚拟DOM
const VNode = React.createElement('h1', {id: 'app'}, '你好');

//2. 渲染虚拟DOM到页面
ReactDOM.render(VNode, document.getElementById("app"));

每次创建一个标签,都需要调用 React.createElement

// 若在 <h1> 里再嵌套 <span>
const VNode = React.createElement('h1', {id: 'app'},  React.createElement('h1', {}, '你好'));

三:关于虚拟DOM

  1. 本质上是一个 Object 类型的对象(一般对象)
typeOf VNode   // Object
VNode instanceOf Object // true
  1. 虚拟DOM比较“轻”,真实DOM比较“重”。因为虚拟DOM只是 react 内部在用,无需真实DOM上那么多属性

  2. 虚拟DOM最终会被 react 转化为真实DOM,呈现在页面上

四:jsx的语法规则

  1. 定义虚拟DOM时,不要写引号
const VNode = "<h1>你好</h1>"  // wrong
const VNode = <h1>你好</h1>    // true
  1. 标签中混入js表达式时,使用 {}
const VNode = <h1 id={myId}>你好</h1>  
  1. 定义样式名用 className
const VNode = <h1 className="myClass">你好</h1>  
  1. 内联样式使用 style={{key: value}} 的形式
  2. 只有一个根标签
  3. 标签必须闭合
  4. 标签首字母小写:将jsx中的标签转化为 html中的同名元素,若html中无该标签对应的同名元素,则报错
  5. 标签首字母大写:react 就去渲染对应的组件,若没有定义该组件,则报错

五:模块与组件、模块化与组件化

1.模块

  • 理解:向外提供特定功能的js程序,一般就是一个js文件
  • 为什么要拆成模块:随着业务逻辑的增加,代码越来越多且复杂
  • 作用:复用js,简化js的编写,提高js运行效率

2.组件

  • 理解:用来实现局部功能效果的 代码和资源 的集合(html / css / js / image 等等)
  • 为什么:一个界面的功能很复杂
  • 作用:复用编码,简化项目代码,提高运行效率

3.模块化

  • 当应用的 js 都以模块来编写,这个应用就是一个模块化的应用

4.组件化

  • 当应用是以多组件的方式实现,这个应用就是一个组件化的应用

六:定义组件

1.函数式组件

// 1.创建函数式组件
function MyComponent() {
	console.log(this); // 此处的 this 是 undefined,因为 babel 编译后开启了严格模式(不指向window)
	return <h1>你好</h1>
}

// 2.渲染组件到页面
ReactDOM.render(<MyComponent />, document.getElementById('app'));

渲染组件到页面时发生了什么?

  1. React 解析组件标签,找到 MyComponent 组件
  2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,再呈现在页面中

2.类式组件

// 1.创建类式组件
class MyComponent extends React.Component {
	render() {
		// render 是放在哪里的? —— MyComponent 的原型对象上,供实例使用
		// render 中的this是谁? —— MyComponent 的实例对象 <=>  MyComponent 组件实例对象
		console.log(this);
		return <h1>你好</h1>
	}
}

// 2.渲染组件到页面
ReactDOM.render(<MyComponent />, document.getElementById('app'));

渲染组件到页面时发生了什么?

  1. React 解析组件标签,找到 MyComponent 组件
  2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法
  3. 将 render 返回的虚拟DOM转为真实DOM,并呈现在页面上

七:类中的this

class MyComponent extends React.Component {
	constructor(props) {
		super(props);
		// 初始化状态
		this.state = {
			isHot: false
		}
	}

	render() {
		const {isHot} = this.state;
		// onClick 调用的是实例上的 changeWeather,而实例上没有,只有原型上有
		return <h1 onClick=this.changeWeather>{isHot? '炎热' : '凉爽'}</h1>
	}

	changeWeather() {
		// changeWeather 放在哪里?—— Weather 的原型对象上,供实例使用
		// 由于 changeWeather 是作为 onClick 的回调,所以不是通过实例调用的,是直接调用
		// 类中的方法默认开启了局部的严格模式,所以 changeWeather 中的 this 为 undefined
		console.log(this); // undefined
	}

}

解决方法:

constructor(props) {
		super(props);
		// 初始化状态
		this.state = {
			isHot: false
		}
		// 解决 changeWeather 中 this 指向问题
		// 左边的表示实例上   右边的表示原型对象上 (原型上的赋给实例)
		this.changeWeather = this.changeWeather.bind(this)
	}

八:setState

react中修改状态 —— 必须通过 setState 进行更新,且更新是一种合并,不是替换。

// 获取原来的值
const isHot = this.state.isHot;
// 赋值
this.setState({isHot: !isHot})

P18.state的简写方式(2021.5.20 周四1)

类中可以直接写赋值语句

class MyComponent extends React.Component {
	
	// 初始化状态
	state = {
		isHot: false
	}

	render() {
		const {isHot} = this.state;
		// onClick 调用的是实例上的 changeWeather,而实例上没有,只有原型上有
		return <h1 onClick=this.changeWeather>{isHot? '炎热' : '凉爽'}</h1>
	}

	// 自定义方法:赋值语句的形式 + 箭头函数
	changeWeather = () => {
		console.log(this); // MyComponent
	}

}

P19.组件三大核心属性:state(2021.5.20 周四2)

1. 理解

  • state 是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)
  • 组件被称为“状态机”,通过更新组件的 state 来更新对应的页面的显示(重新渲染组件)

2. 注意

  • 组件中 render 方法中的 this 为组件实例对象

  • 组件自定义方法中 this 为 undefined,如何解决?

  • —— a. 强制绑定 this:通过函数对象的 bind();

  • —— b. 箭头函数;

  • 状态数据,不能直接修改或更新,要通过 setState

P22.对 props 进行限制(2021.5.20 周四3)

class Person extends React.Component {
	render() {
		const {name, age, sex} = this.props;
		return (
			<ul>
				<li>姓名:{name}</li>
				<li>年龄:{age+1}</li>
				<li>性别:{sex}</li>
			</ul>
		)
	}
}

// 对标签属性进行 类型、必要性  的限制
Person.propTypes = {
	name: PropTypes.string.isRequired,
	age: PropTypes.number,
	name: PropTypes.string,
	speak: PropType.func // 函数 
}

// 指定默认的标签属性
Person.defaultProps  = {
	sex: '男',
	age: 18
}

const p = {name: 'zs', age: 18, sex: '男'};

function speak() {
	console.log('speaking……')
}

ReactDOM.render(<Person {...p} speak={speak}/>, document.getElementById('app'));

P23. props的简写(2021.5.22 周六1)

1. 给类的实例添加属性

class Person {
	height = 170;
}

2. 给类本身添加属性

// 1. static
class Person {
	static height = 170;
}

// 2. 在类的外部加
Person.height = 170;

3. 简写: 把限制条件放入类中

class Person extends React.Component {
	// 对标签属性进行 类型、必要性  的限制
	static propTypes = { }
	
	// 指定默认的标签属性
	static defaultProps  = { }

	render() {}
}

P24. 类式组件中的构造函数(2021.5.22 周六2)

构造函数仅用于以下两种情况

constructor(props) {
	super(props);
	// 1. 初始化状态
	this.state = { isHot: false }
	// 2. 为事件处理函数绑定实例
	this.changeWeather = this.changeWeather.bind(this)
}

但一般不用构造函数,而使用简写的方式代替

// 初始化状态
state = { isHot: false } 

// 自定义方法:赋值语句的形式 + 箭头函数
changeWeather = () => { }

P25. 函数式组件使用 props(2021.5.22 周六3)

props 作为函数参数来传递:组件标签的所有属性都保存在 props 中

// 父组件
<Person {...this.state}/>

// 子组件
export default function Person(props) {
    return (
        <div>
            <p>{props.name}</p>
            <p>{props.age}</p>
        </div>
    )
}

// 对标签属性进行 类型、必要性  的限制
Person.propTypes = { }

// 指定默认的标签属性
Person.defaultProps  = { }

P26. 总结 props(2021.5.22 周六4)

理解:

  • 每个组件对象都会有 props(properties的简写)属性
  • 组件标签的所有属性都保存在 props 中

作用:

  • 通过标签属性从组件外 向 组件内传递变化的数据
  • 注意:组件内部不用修改 props 数据

扩展属性

  • 对象的所有属性都通过 props 传递
<Person {...person}/>

P27-31. ref的使用(2021.5.23 周日1)

1.字符串形式的 ref (不推荐)

<input ref="input1"/>

getValue = () => {
	alert(this.refs.input1.value);
}

2. 回调形式的 ref

<input ref={(currentNode) => {this.input1 = currentNode}}/>

getValue = () => {
   alert(this.input1.value);
}

3. createRef 创建 ref 容器

<input ref={this.myRef}/>

// React.createRef 调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点
// 每创建一个ref,都需要调用一次 React.createRef,该容器是“专人专业”的
myRef = React.createRef()

getValue = () => {
   alert(this.myRef.current.value);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值