文章目录
认识React
React是一个用于构建用户界面的JavaScript库,可以用来构建 Web 应用(使用ReactDOM)(不止如此,还有React Native)。
react-dom:渲染 Web、react-native:构建手机应用
React 是基于组件的,在React中用组件来表示页面中的部分内容,通过组合、复用多个组件,就可以实现完整的页面功能。
React主要有2个包,react包是核心,提供创建元素、组件等功能,react-dom 包提供 DOM 渲染等相关功能。
基本使用
React 安装
npm i react react-dom
// 引入 react、react-dom 的 js 文件
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
<script>
// 创建 React 元素
const title = React.createElement('h1', null, 'Hello React');
// 渲染 React 元素到 root 节点下
ReactDom.render(title, document.getElementById('root'));
</script>
使用 React 脚手架
初始化项目:
npx create-react-app my-app
index.js:
import React from 'react'
import ReactDOM from 'react-dom'
const title = React.createElement('h1', null, 'Hello, React!!!');
ReactDOM.render(title, document.getElementById('root'));
启动项目
npm start
JSX
JSX 是 JavaScript XML 的简写,表示在 JavaScript 代码中写 XML(HTML)格式的代码。
声明式语法更直观,与HTML结构相同
const title =(<h1>Hello, JSX!</h1>); // JSX 语法,创建 react 元素
ReactDOM.render(title, document.getElementById('root'));
JSX不是标准的 ECMAScript 语法,它是 ECMAScript 的语法扩展,需要使用 babel 编译处理后才能在浏览器环境中使用(编译JSX语法的包:@babel/preset-react)
React 元素的属性名使用的是驼峰命名法,一些特殊属性名和 HTML 属性名有些区别:
class => className、for => htmlFor、tabindex => tabIndex
另外没有子节点的 React 元素可以用 />结束(JSX中的约定)。
嵌入 JS 表达式
语法:{js 表达式}
const name = 'Qanx';
const div = (<div>Hello, {name}</div>);
ReactDOM.render(div, document.getElementById('root'));
JSX条件渲染
根据条件渲染特定的JSX结构。
const loadData1 = () => {
return (isLoding ? <div>loading……</div> : <div>数据加载完成1</div>);
};
const loadData2 = () => {
return (isLoding && <div>loading1……</div>); // 逻辑与运算符, 逻辑中断
};
JSX列表渲染
渲染一组数据,使用数组的map()
方法,map 会返回处理后的数据。
渲染列表时应该添加 key 属性,key属性的值要保证唯一
const songs = [{ id: 1, name: '痴心绝对' }, { id: 2, name: '像我这样的人' }, { id: 3, name: '南山南' }];
const test = [<li key='1'>痴心绝对</li>, <li key='2'>像我这样的人</li>, <li key='4'>南山南</li>];
const div = (
<div>
<ul>
{songs.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
<ul>{test}</ul>
</div>
);
ReactDOM.render(div, document.getElementById('root'));
JSX样式处理
行内样式:
const div = (
<div style={{ color: 'red',backgroundColor: 'skyblue' }}>Hello</div> // 样式属性同样遵循驼峰命名
);
外部样式(className):
.testDiv {
background-color: skyblue
}
import './css/index.css'
const div = (<div className='testDiv'>Hello</div>);
React完全利用JS语言自身的能力来编写UI,而不是造轮子增强HTML功能
React组件
组件是 React 的核心内容,使用 React 就是在使用组件。 React组件是独立的,组件表示页面中的部分功能,通过复用、组合可以实现完整页面功能。
函数组件
函数组件是指使用 JS 的函数(或箭头函数)创建的组件。约定:
- 函数的名称必须以大写字母开头
- 函数组件必须有返回值,表示该组件的结构
- 返回值为 null,则表示不渲染任何内容
import React from 'react';
import ReactDOM from 'react-dom/client';
const Hello = () => (<div>Hello, 函数组件!</div>);
const root = ReactDOM.createRoot(document.getElementById('root')); // createRoot 为 react 18新语法, 在包 react-dom/client 中
root.render(<Hello />);
类组件
类组件是指使用 ES6 的 class 创建的组件。约定:
- 类名称必须以大写字母开头
- 类组件应该继承
React.Component
父类,从而可以使用父类中提供的方法或属性 - 类组件必须提供
render()
方法,且方法必须有返回值,表示该组件的结构
import React from 'react';
import ReactDOM from 'react-dom/client';
class Hello extends React.Component {
render () {
return (<div>Hello, 类组件!</div>);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello />);
组件作为一个独立的个体,一般都会放到一个单独的JS文件中
组件抽离为独立的 js 文件
import React from 'react'
//const Hello = () => (<div>Hello, 函数组件!</div>);
class Hello extends React.Component {
render () {
return (<div>Hello, 类组件!</div>);
}
}
export default Hello // 导出 Hello 组件
import React from 'react'
import ReactDOM from 'react-dom/client'
import Hello from './Hello';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello />);
React 事件处理
React 事件绑定语法与 DOM 事件语法贴近:
- 语法:on+事件名称={事件处理},如:onClick={()=>console.log(‘click’)}
- React 事件采用驼峰命名法
import React from "react";
// 1. 类组件
// class App extends React.Component {
// handleClick () {
// console.log("单击事件触发了")
// }
// render () {
// return (<button onClick={this.handleClick}>按钮</button>);
// }
// }
// 2. 函数组件
const App = () => {
function handleClick () {
console.log("单击事件触发了");
}
return (<button onClick={handleClick}>按钮</button>);
};
export default App;
事件对象
通过事件处理程序的参数获取到事件对象。React 中的事件对象叫做:合成事件(对象)
合成事件:兼容所有浏览器,不用担心跨浏览器兼容性问题
const App = () => {
function handleClick (e) {
e.preventDefault(); // 阻止浏览器的默认行为
console.log('事件对象', e);
}
return (<a href="http://www.baidu.com" onClick={handleClick}>百度</a>);
};
有状态组件和无状态组件
函数组件又叫无状态组件,类组件又叫做有状态组件。
- 状态(state)即数据
- 函数组件没有自己的状态,只负责数据展示
- 类组件有自己的状态,负责更新UI,让页面“动”起来
state
状态(State)即数据,是组件内部的私有数据,只能在组件内部使用。
state的值是一个对象,表示一个组件中可以有多个数据
class Timer extends React.Component {
constructor() {
super();
this.state = { count: 0 }; // 初始化 state
}
// state = { count: 0 }; // 简化语法
render () {
return (
<div>
<h1>Timer: {this.state.count}</h1>
</div>
);
}
}
setState()修改状态
状态是可以改变的,语法:this.setState({要修改的数据})
。
- 不要直接修改 state 中的值,而是通过 setState 方法修改
- setState 的作用有两个:①修改state、②更新UI(更新UI会重新渲染UI,所以直接修改state页面是不会发生改变的)
class Timer extends React.Component {
state = { count: 0 };
render () {
return (
<div>
<h1>Timer: {this.state.count}</h1>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>+1</button>
</div>
);
}
}
数据驱动视图的思想
抽离事件处理函数:
class Timer extends React.Component {
state = { count: 0 };
onIncrement () {
this.setState({ count: this.state.count + 1 }); // 这里调用时,this 为 undefined
}
render () {
return (
<div>
<h1>Timer: {this.state.count}</h1>
<button onClick={this.onIncrement}>+1</button>
</div>
);
}
}
上面代码中 this 为 undefined
事件绑定中 this 指向
箭头函数
利用箭头函数自身不绑定 this 的特性,让 this 指向外部环境的 this:
class Timer extends React.Component {
state = { count: 0 };
onIncrement () {
this.setState({ count: this.state.count + 1 }); // 这里 this 指向调用的 this
}
render () {
// 箭头函数中的 this 执行外部环境,这里是 render() 方法
return (
<div>
<h1>Timer: {this.state.count}</h1>
<button onClick={() => this.onIncrement()}>+1</button>
</div>
);
}
}
Function.prototype.bind()
使用 ES5 中的 bind() 方法,将事件处理程序中的 this 与组件实例绑定到一起。
class Timer extends React.Component {
constructor() {
super();
this.state = { count: 0 };
// 1. bind() 函数会创建一个新的绑定函数, 它包装了原函数对象, 这个新函数的 this 被指定为 bind() 的第一个参数
// 2. bind() 函数返回一个原函数的拷贝(新的绑定函数), 然后重新赋值给原来的函数
// 3. 调用绑定函数通常会导致执行包装函数
this.onIncrement = this.onIncrement.bind(this);
}
onIncrement () {
this.setState({ count: this.state.count + 1 });
}
render () {
return (
<div>
<h1>Timer: {this.state.count}</h1>
<button onClick={this.onIncrement}>+1</button>
</div>
);
}
}
class 的实例方法
利用箭头函数形式的 class 实例方法:
class Timer extends React.Component {
state = { count: 0 };
onIncrement = () => this.setState({ count: this.state.count + 1 }); // this 指向的是当前 Timer 实例
render () {
return (
<div>
<h1>Timer: {this.state.count}</h1>
<button onClick={this.onIncrement}>+1</button>
</div>
);
}
}
表单处理
受控组件
React 将 state 与表单元素的值 value 绑定到一起,由 state 的值来控制表单元素的值,这种受 React 控制的表单元素又叫做受控组件。使用步骤:
- 在 state 中添加一个状态,作为表单元素的 value 值(控制表单元素值的来源为 state)
- 给表单元素绑定 change 事件,将表单元素的值设置为 state 值(控制表单元素值的变化)
class Form extends React.Component {
state = { name: '', gender: '1', isChecked: true, desc: '' };
handleForm = (e) => {
const target = e.target; // 获取当前 DOM 对象
const value = target.type === 'checkbox' ? target.checked : target.value; // 根据类型获取值
this.setState({ [target.name]: value }); // 设置对象的值(属性名表达式语法)
};
render = () => (
<div>
<input type="text" name="name" value={this.state.name} onChange={this.handleForm} /><br />
<select name="gender" value={this.state.gender} onChange={this.handleForm}>
<option value='1'>男</option>
<option value='0'>女</option>
</select><br />
<div>
<input type='checkbox' name="isChecked" checked={this.state.isChecked} onChange={this.handleForm} />看电影
</div>
<textarea name="desc" value={this.state.desc} onChange={this.handleForm}></textarea>
<div>
name: {this.state.name}<br />
gender: {this.state.gender}<br />
isChecked: {this.state.isChecked.toString()}<br />
desc: {this.state.desc}
</div>
</div>
);
}
属性名表达式语法:属性名表达式
非受控组件
原生 DOM,不受 React state 管理的表单元素,使用步骤:
- 调用
React.createRef()
方法创建一个 ref 对象 - 将创建好的 ref 对象添加到表单元素
- 通过 ref 对象获取到对应表单元素的值
class Form extends React.Component {
constructor() {
super();
this.txtRef = React.createRef();
}
inputChange = () => {
console.log(this.txtRef.current.value);
};
render = () => {
return (
<div>
<input type="text" ref={this.txtRef} onChange={this.inputChange} />
</div>
);
};
}
本文系B站黑马前端React教程学习笔记。