React 基本使用

create-react-app

创建 react 项目的脚手架。

React 基本用法

jsx 语法

变量、表达式

import React from 'react';class JSXBaseDemo extends React.Component {constructor(props) {super(props);this.state = {name: '章三'};}render() {// 获取变量 插值const pElem = <p>{this.state.name}</p>;return pElem;// // 表达式// const exprElem = <p>{this.state.flag ? 'yes' : 'no'}</p>;// return exprElem;}
}export default JSXBaseDemo;

class、style

/* style.css */
.title {font-size: 30px;color: red;
}
import React from 'react';
import './style.css';class JSXBaseDemo extends React.Component {constructor(props) {super(props);this.state = {};}render() {// classconst classElem = <p className="title">设置 css class</p>;return classElem;// // style// const styleData = { fontSize: '30px',  color: 'blue' };// const styleElem = <p style={styleData}>设置 style</p>;// // 内联写法,注意 {{ 和 }}// // const styleElem = <p style={{ fontSize: '30px',  color: 'blue' }}>设置 style</p>;// return styleElem;}
}export default JSXBaseDemo;

子元素和组件

import React from 'react';
import List from '../List';class JSXBaseDemo extends React.Component {constructor(props) {super(props);this.state = {imgUrl: 'https://img1.mukewang.com/5a9fc8070001a82402060220-140-140.jpg'};}render() {// 子元素const imgElem = <div><p>我的头像</p><img src="xxxx.png"/><img src={this.state.imgUrl}/></div>;return imgElem';// // 加载组件// const componentElem = <div>//     <p>JSX 中加载一个组件</p>//     <hr />//     <List />// </div>;// return componentElem;}
}export default JSXBaseDemo;

原生 html

import React from 'react';class JSXBaseDemo extends React.Component {constructor(props) {super(props);this.state = {};}render() {// 原生 htmlconst rawHtml = '<span>富文本内容<i>斜体</i><b>加粗</b></span>';const rawHtmlData = {__html: rawHtml // 注意,必须是这种格式};const rawHtmlElem = <div><p dangerouslySetInnerHTML={rawHtmlData}></p><p>{rawHtml}</p></div>;return rawHtmlElem;}
}export default JSXBaseDemo;

条件

  • if else
  • 三元表达式
  • 逻辑运算符:&&||
.btn-white {color: #333;
}
.btn-black {background-color: #666;color: #fff;;
}
import React from 'react';
import './style.css';class ConditionDemo extends React.Component {constructor(props) {super(props);this.state = {theme: 'black'};}render() {const blackBtn = <button className="btn-black">black btn</button>;const whiteBtn = <button className="btn-white">white btn</button>;// // if else// if (this.state.theme === 'black') {//     return blackBtn;// } else {//     return whiteBtn;// }// // 三元运算符// return <div>//     { this.state.theme === 'black' ? blackBtn : whiteBtn }// </div>;// &&return <div>{ this.state.theme === 'black' && blackBtn }</div>;}
}export default ConditionDemo;

列表渲染

  • map
  • key
import React from 'react';class ListDemo extends React.Component {constructor(props) {super(props);this.state = {list: [{id: 'id-1',title: '标题1'},{id: 'id-2',title: '标题2'},{id: 'id-3',title: '标题3'}]};}render() {return <ul>{this.state.list.map((item, index) => {// 这里的 key 和 Vue 的 key 类似,必填,不能是 index 或 randomreturn <li key={item.id}>index {index}; id {item.id}; title {item.title}</li>;})}</ul>;}
}export default ListDemo;

事件

bind this

  • 非严格模式下,dom 事件中的 this 都是运行时的,就是浏览器执行的,指向的是 window
  • 严格模式下,这里的 this 指向 undefined

箭头函数为什么能解决 bind this

  • 箭头函数的 this 永远指向上级作用域。
  • 箭头函数的 this 是在定义函数时绑定的,不是在执行过程中绑定的。
  • 也就是说,函数在定义时,this 就继承了定义函数的对象。
import React from 'react';class EventDemo extends React.Component {constructor(props) {super(props);this.state = {name: 'zhangsan'};// 修改方法的 this 指向this.clickHandler1 = this.clickHandler1.bind(this);}render() {// this - 使用 bindreturn <p onClick={this.clickHandler1}>{this.state.name}</p>;// // this - 使用静态方法// return <p onClick={this.clickHandler2}>//     clickHandler2 {this.state.name}// </p>;}clickHandler1() {// console.log('this....', this) // this 默认是 undefinedthis.setState({name: 'lisi'});}// 静态方法,this 指向当前实例clickHandler2 = () => {this.setState({name: 'lisi'});}
}export default EventDemo;

关于 event 参数

import React from 'react';class EventDemo extends React.Component {constructor(props) {super(props);this.state = {};}render() {// eventreturn <a href="https://imooc.com/" onClick={this.clickHandler3}>click me</a>;}// 获取 eventclickHandler3 = (event) => {// 阻止默认行为event.preventDefault(); // 阻止冒泡event.stopPropagation(); // 指向当前元素,即当前元素触发console.log('target', event.target); // 指向当前元素,假象!!!console.log('current target', event.currentTarget); // 注意,event 其实是 React 封装的。// 可以看 __proto__.constructor 是 SyntheticEvent 组合事件// 不是原生的 Event ,原生的 MouseEventconsole.log('event', event); console.log('event.__proto__.constructor', event.__proto__.constructor);// 原生 event 如下。其 __proto__.constructor 是 MouseEventconsole.log('nativeEvent', event.nativeEvent);// 指向当前元素,即当前元素触发console.log('nativeEvent target', event.nativeEvent.target); // 指向 document !!!console.log('nativeEvent current target', event.nativeEvent.currentTarget;); // 1. event 是 SyntheticEvent ,模拟出来 DOM 事件所有能力// 2. event.nativeEvent 是原生事件对象// 3. 所有的事件,都被挂载到 document 上 (React17 事件绑定到 root 上)// 4. 和 DOM 事件不一样,和 Vue 事件也不一样}
}export default EventDemo;

传递自定义参数

import React from 'react';class EventDemo extends React.Component {constructor(props) {super(props);this.state = {list: [{id: 'id-1',title: '标题1'},{id: 'id-2',title: '标题2'},{id: 'id-3',title: '标题3'}]};}render() {// 传递参数 - 用 bind(this, a, b)return <ul>{this.state.list.map((item, index) => {return <li key={item.id} onClick={this.clickHandler4.bind(this, item.id, item.title)}>index {index}; title {item.title}</li>;})}</ul>;}// 传递参数// 最后追加一个参数,即可接收 eventclickHandler4(id, title, event) {console.log(id, title);console.log('event', event); }
}export default EventDemo;

组件和 props (类型检查)

受控组件

  • 表单的值受 state 控制。
  • value 指向 stateonChange 事件监听,使用 setState 修改值。
import React from 'react';class FormDemo extends React.Component {constructor(props) {super(props);this.state = {name: 'zhangsan'};}render() {// 受控组件return <div><p>{this.state.name}</p><label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}<input id="inputName" value={this.state.name} onChange={this.onInputChange} /></div>;}onInputChange = (e) => {this.setState({name: e.target.value});}
}export default FormDemo;

表单的使用

import React from 'react';class FormDemo extends React.Component {constructor(props) {super(props);this.state = {name: 'zhangsan',info: '个人信息',city: 'beijing',flag: true,gender: 'male'};}render() {// // 受控组件// return <div>//     <p>{this.state.name}</p>//     <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}//     <input id="inputName" value={this.state.name} onChange={this.onInputChange}/>// </div>;// textarea - 使用 valuereturn <div><textarea value={this.state.info} onChange={this.onTextareaChange}/><p>{this.state.info}</p></div>;// // select - 使用 value// return <div>//     <select value={this.state.city} onChange={this.onSelectChange}>//         <option value="beijing">北京</option>//         <option value="shanghai">上海</option>//         <option value="shenzhen">深圳</option>//     </select>//     <p>{this.state.city}</p>// </div>;// // checkbox// return <div>//     <input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/>//     <p>{this.state.flag.toString()}</p>// </div>;// // radio// return <div>//     male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/>//     female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/>//     <p>{this.state.gender}</p>// </div>;}onInputChange = (e) => {this.setState({name: e.target.value});}onTextareaChange = (e) => {this.setState({info: e.target.value});}onSelectChange = (e) => {this.setState({city: e.target.value});}onCheckboxChange = () => {this.setState({flag: !this.state.flag});}onRadioChange = (e) => {this.setState({gender: e.target.value});}
}export default FormDemo;

组件使用

  • props 传递数据
  • props 传递函数
  • props 类型检查
import React from 'react';
import PropTypes from 'prop-types';class Input extends React.Component {constructor(props) {super(props);this.state = {title: ''};}render() {return <div><input value={this.state.title} onChange={this.onTitleChange}/><button onClick={this.onSubmit}>提交</button></div>;}onTitleChange = (e) => {this.setState({title: e.target.value});}onSubmit = () => {const { submitTitle } = this.props;submitTitle(this.state.title); // 'abc'this.setState({title: ''});}
}// props 类型检查
Input.propTypes = {submitTitle: PropTypes.func.isRequired
};class List extends React.Component {constructor(props) {super(props);}render() {const { list } = this.props;return <ul>{list.map((item, index) => {return <li key={item.id}><span>{item.title}</span></li>;})}</ul>;}
}
// props 类型检查
List.propTypes = {list: PropTypes.arrayOf(PropTypes.object).isRequired
};class Footer extends React.Component {constructor(props) {super(props);}render() {return <p>{this.props.text}{this.props.length}</p>;}
}class TodoListDemo extends React.Component {constructor(props) {super(props);// 状态(数据)提升this.state = {list: [{id: 'id-1',title: '标题1'},{id: 'id-2',title: '标题2'},{id: 'id-3',title: '标题3'}],footerInfo: '底部文字'};}render() {return <div><Input submitTitle={this.onSubmitTitle}/><List list={this.state.list}/><Footer text={this.state.footerInfo} length={this.state.list.length}/></div>;}onSubmitTitle = (title) => {this.setState({list: this.state.list.concat({id: `id-${Date.now()}`,title})});}
}export default TodoListDemo;

state 和 setState

setState

  • 不可变值
  • 可能是异步更新 (针对 React <= 17)
    • 直接使用是异步更新,在第二个参数的回调函数中可以拿到最新的 state
    • setTimeout 中使用是同步
    • 自定义的 dom 事件,是同步的
  • 可能会被合并 (针对 React <= 17)
    • 异步更新,setState 传入的参数是对象,那么在更新前会被合并
    • 异步更新,setState 传入的参数是函数,不会被合并
import React from 'react';class StateDemo extends React.Component {constructor(props) {super(props);// 第一,state 要在构造函数中定义this.state = {count: 0};}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>;}increase = () => {// // 第二,不要直接修改 state ,要使用不可变值 -----------------------// // this.state.count++; // 错误// this.setState({//     count: this.state.count + 1 // SCU// });// 操作数组、对象的的常用形式// 第三,setState 可能是异步更新(有可能是同步更新) ------------------// this.setState({//     count: this.state.count + 1// }, () => {//     // 联想 Vue $nextTick - DOM//     // 回调函数中可以拿到最新的 state//     console.log('count by callback', this.state.count); // });// console.log('count', this.state.count); // 异步的,拿不到最新值// // setTimeout 中 setState 是同步的// setTimeout(() => {//     this.setState({//         count: this.state.count + 1//     });//     console.log('count in setTimeout', this.state.count);// }, 0);// 自己定义的 DOM 事件,setState 是同步的。// 第四,state 异步更新的话,更新前会被合并 --------------------------// // 传入对象,会被合并(类似 Object.assign )。执行结果只一次 +1// this.setState({//     count: this.state.count + 1// });// this.setState({//     count: this.state.count + 1// });// this.setState({//     count: this.state.count + 1// });// 传入函数,不会被合并。执行结果是 +3this.setState((prevState, props) => {return {count: prevState.count + 1};});this.setState((prevState, props) => {return {count: prevState.count + 1};});this.setState((prevState, props) => {return {count: prevState.count + 1};});}// bodyClickHandler = () => {//     this.setState({//         count: this.state.count + 1//     });//     console.log('count in body event', this.state.count);// }// componentDidMount() {//     // 自己定义的 DOM 事件,setState 是同步的//     document.body.addEventListener('click', this.bodyClickHandler);// }// componentWillUnmount() {//     // 及时销毁自定义 DOM 事件//     document.body.removeEventListener('click', this.bodyClickHandler);//     // clearTimeout// }
}export default StateDemo;// -------------------------- 我是分割线 -----------------------------// // 不可变值(函数式编程,纯函数) - 数组
// const list5Copy = this.state.list5.slice();
// list5Copy.splice(2, 0, 'a'); // 中间插入/删除
// this.setState({
//     list1: this.state.list1.concat(100), // 追加
//     list2: [...this.state.list2, 100], // 追加
//     list3: this.state.list3.slice(0, 3), // 截取
//     list4: this.state.list4.filter(item => item > 100), // 筛选
//     list5: list5Copy // 其他操作
// });
// // 注意,不能直接对 this.state.list 进行 push pop shift unshift splice 等,这样违反不可变值// // 不可变值 - 对象
// this.setState({
//     obj1: Object.assign({}, this.state.obj1, {a: 100}),
//     obj2: {...this.state.obj2, a: 100}
// })
// // 注意,不能直接对 this.state.obj 进行属性设置,这样违反不可变值

React18 中的 setState

  • React 组件事件:异步更新 + 合并 state
  • DOM 事件、setTimeout:异步更新 + 合并 state
  • Automatic Batching 自动批处理
import { useState, useEffect } from 'react';function useStateDemo() { const [value, setValue]= useState(100);function clickHandler() { // // 合并后 +1// setValue(value + 1); // setValue(value + 1); // setValue(value + 1); // console.log(value); // 100 异步更新 setTimeout(() => {// 合并后 +1setValue(value + 1); setValue(value + 1); setValue(value + 1); console.log(value); // 100 异步更新 });} useEffect(() =>{ // 自绑定 DOM 事件 document.getElementById('btn2').addEventListener('click', () => { // 合并后 +1setValue(value + 1); setValue(value + 1); setValue(value + 1); console.log(value); // 100 异步更新 });});return <div> <span>{value}</span> <button onClick={clickHandler}>increase1</button> <button id="btn2">increase2</button> </div>;
}
  • React <= 17:只有 React 组件事件才批处理(合并 + 异步)
  • React18:所有事件都自动批处理 Automatic Batching

组件生命周期

react 生命周期图示

在这里插入图片描述

  • 初始化阶段:constructor
  • 挂载阶段:componentDidMount
  • 更新阶段:componentDidUpdate
  • 卸载阶段:componentWillUnmount

展示不常用的生命周期图示

在这里插入图片描述

  • shouldComponentUpdate:可以控制是否更新

父子组件生命周期

  • 父组件先 constructor,然后子组件才 constructor
  • 子组件先 componentDidMount,然后父组件 componentDidMount
  • 子组件先 componentDidUpdate,然后父组件 componentDidUpdate
  • 父组件先触发 componentWillUnmout,然后子组件触发 componentWillUnmount

FQA

  1. React 事件为何 bind this
    • 非严格模式下,dom 事件中的 this 都是运行时的,就是浏览器执行的,指向的是 window
    • 严格模式下,这里的 this 指向 undefined
  2. 箭头函数为什么能解决 bind this
    • 箭头函数的 this 永远指向上级作用域:箭头函数的 this 是在定义函数时绑定的,不是在执行过程中绑定的。也就是说,函数在定义时,this 就继承了定义函数的对象。
  3. react 的事件和 vue 的区别。
    • vue 的事件是原生 eventMouseEvent),事件是绑定在当前元素上的
    • react 的事件是 SyntheticEventReact16 事件是绑定在 document 上的,React17 后是绑定在 root 上的;react 获取原生事件是通过 event.nativeEvent 获取。
  4. react 为什么对事件对象进行二次封装?
    • 兼容各个平台,不仅仅是 DOM ,如 react native
  5. React17 为什么将事件绑定到 root 上?
    • 有利于多个 React 版本并存(document 只有一个,而 root 可以有多个),例如微前端。
      在这里插入图片描述
  6. 描述 react 组件的生命周期。
  • 初始化阶段:constructor
  • 挂载阶段:componentDidMount
  • 更阶段:componentDidUpdate
  • 卸载阶段:componentWillUnmount
  • 在更新阶段 componentDidUpdate 之前还有一个 shouldComponentUpdate:可以控制是否更新
  1. react 组件如何通讯?
    • 父子组件通过 props 传递数据
    • 可通过 context 从顶层组件向子孙组件进行下发数据
    • 使用 redux 可以全局组件共享状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/338701.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

冲刺2024年AMC8模拟题:往年真题限时练一练和答案详解(4)

今天距离2024年AMC8正式比赛还有一周时间了&#xff0c;很多城市的中小学已经基本上放假了&#xff0c;所以参加AMC8竞赛的同学&#xff0c;可以在将更多的时间用在冲刺AMC8竞赛备考了&#xff0c;寒假作业的时间接下来几天可以少一点&#xff0c;AMC8结束后可以再多一点。 今…

vue element-ui的table列表中展示缩略图片效果实例

这篇文章主要给大家介绍了关于vue element-ui的table列表中展示多张图片(可放大)效果的相关资料,文中通过代码示例介绍的非常详细,需要的朋友可以参考下 一、效果图 二、代码部分 1、原理 使用 <el-table-column> 和 <el-image> 组件来在表格中插入缩略图 2、te…

论文阅读《Generalizing Face Forgery Detection with High-frequency Features》

高频噪声分析会过滤掉图像的颜色内容信息。 本文设计了三个模块来充分利用高频特征&#xff0c; 1.多尺度高频特征提取模块 2.双跨模态注意模块 3.残差引导空间注意模块&#xff08;也在一定程度上体现了两个模态的交互&#xff09; SRM是用于过滤图像的高频噪声 输入的图…

国产服务器 BIOS下组建RADI不同RAID卡-超详细

国产服务器 长城 组建Raid的方法 说明 大多数国产服务器通用型服务器进入BIOS的都是按DEL键。 9361RAID卡组建方法 在服务器启动过程中&#xff0c;按下DEL键进入BIOS界面。 进入设备管理器&#xff0c;选择AVAGO MegaRAID页签。 3. 进入RAID卡设备&#xff0c;选择Main Me…

赋能智慧农业生产,基于YOLOv7开发构建农业生产场景下油茶作物成熟检测识别系统

AI赋能生产生活场景&#xff0c;是加速人工智能技术落地的有利途径&#xff0c;在前文很多具体的业务场景中我们也从实验的角度来尝试性地分析实践了基于AI模型来助力生产生活制造相关的各个领域&#xff0c;诸如&#xff1a;基于AI硬件实现农业作物除草就是一个比较熟知的场景…

LeetCode 232.用栈实现队列(详解) (๑•̌.•๑)

题目描述&#xff1a; 解题思路&#xff1a; 创建两个栈&#xff0c;一个用于入数据&#xff0c;一个用于出数据。分别是pushST和popST; 1.如果是入数据就直接入进pushST 2.如果是出数据&#xff0c;先检查popST中有无数据&#xff0c;如果有数据&#xff0c;就直接出。如果没…

Netty-Netty基础应用与了解

前言 Netty 的优势 1、 API 使用简单&#xff0c;开发门槛低&#xff1b; 2、功能强大&#xff0c;预置了多种编解码功能&#xff0c;支持多种主流协议&#xff1b; 3、定制能力强&#xff0c;可以通过 ChannelHandler 对通信框架进行灵活地扩展&#xff1b; 4、性能高…

Android通过Recyclerview实现流式布局自适应列数及高度

调用 FlowAdapter 跟普通recyclerview一样使用 RecyclerView rvLayout holder.getView(R.id.spe_tag_layout); FlowAdapter rvAdapter new FlowAdapter(); FlowLayoutManager flowLayoutManager new FlowLayoutManager(); rvLayout.setLayoutManager(flowLayoutManager); r…

CentOS 6 制作openssl 1.1.1w rpm包 —— 筑梦之路

参考资料&#xff1a; CentOS 7 制作openssl 1.1.1w 版本rpm包 —— 筑梦之路_centos7 openssl 1.1.1 rpm包-CSDN博客 直接上spec文件如下&#xff1a; Name: openssl Version: 1.1.1w Release: 1%{?dist} Summary: Utilities from the general purpose cryptography li…

Kubernetes/k8s的存储卷/数据卷

k8s的存储卷/数据卷 容器内的目录和宿主机的目录挂载 容器在系统上的生命周期是短暂的&#xff0c;delete&#xff0c;k8s用控制创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态 一旦回到初始状态&#xff0c;所有的后天编辑的文件都会消失…

C++从零基础到入门(1)

目录 一、输入输出 (iostream库) 1.标准输出流cout 2.标准输入流cin 3.标准库iostream &#xff08;1&#xff09;iostream中的窄字符&#xff08;char&#xff09; &#xff08;2&#xff09;iostream中的 宽字符&#xff08;wchar_t&#xff09; 二、变量与数据类型 …

基于DNA的密码学和隐写术综述

摘要 本文全面调研了不同的脱氧核糖核酸(DNA)-基于密码学和隐写术技术。基于DNA的密码学是一个新兴领域,利用DNA分子的大规模并行性和巨大的存储容量来编码和解码信息。近年来,由于其相对传统密码学方法的潜在优势,如高存储容量、低错误率和对环境因素的抗性,该领域引起…