学习react的笔记
react 项目 npm i 安装依赖报错
1
| 创建react工程,提示错误The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "10.5.0",导致一直没有创建成功
|
node版本不一致
- 升级node
1 2 3 4 5 6 7 8
| // 第一步:使用npm安装n模块,n模块是专门用来管理nodejs版本的,名字就叫n执行命令 npm install -g n // (注意不带sudo,我按照网上带sudo提示错误) // 出现此日志表示添加n包成功 // 第二步:使用n模块升级node // 第一种是升级到最新版本 sudo n latest // 第二种是升级到稳定版本(建议用稳定版本) sudo n stable
|
- 如果更新了node或许或导致其他工程有问题,不能轻易更新,可以输入命令行,也可以恢复正常
1
| yarn config set ignore-engines true
|
采用了第二种安装,别人的项目拉取node版本不同也能解决
参考
项目初始–vite配置项目路径别名
参考
核心思想
Vue 早期定位是尽可能的降低前端开发的门槛(这跟 Vue 作者是独立开发者也有关系)。所以 Vue 推崇灵活易用(渐进式开发体验),数据可变,双向数据绑定(依赖收集)。
React 早期口号是 Rethinking Best Practices(重新思考最佳实践)。背靠大公司 Facebook 的 React,从开始起就不缺关注和用户,而且 React 想要做的是用更好的方式去颠覆前端开发方式(事实上跟早期 jquery 称霸前端,的确是颠覆了)。所以 React 推崇函数式编程(纯组件),数据不可变以及单向数据流。函数式编程最大的好处是其稳定性(无副作用)和可测试性(输入相同,输出一定相同),所以通常大家说的 React 适合大型应用,根本原因还是在于其函数式编程。
由于两者核心思想的不同,所以导致 Vue 和 React 许多外在表现不同(从开发层面看)。
掘金
总体感受–一些区别
- vue 更简单,更方便,熟悉了 api 以后,实现某些简单功能更快。react 写法更偏向于原生 JS,Class 的写法不是很舒服,个人更喜欢 hooks。
- 熟悉了 hooks 以后,写起来很自由,不用关心 vue 中固定的 options api
- react 做中后台优势更大,有大厂加持,生态更好,组件库功能也更多,解决方案也更多
- vue2.x 对 typescript 不太友好,react + typescript 更加舒适,两者写起来风格差距较大。
- react JSX 写起来还是不够熟练,onClick、style、className 等等,没有 v-if,v-for,All in JS。Vue 则推崇 html、js、css 分离的写法,当然 vue 也可以写 JSX
- vue 的 prop 必须在子组件 props 字段里声明。React 的 prop 不强制声明,直接使用,如果用 TS 的话还是要声明的
React 是什么?
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
JSX基础
- JSX介绍
概念:JSX是 JavaScript XML(HTML)的缩写,表示在 JS 代码中书写 HTML 结构
作用:在React中创建HTML结构(页面UI结构)
优势
- 采用类似于HTML的语法,降低学习成本,会HTML就会JSX
- 充分利用JS自身的可编程能力创建HTML结构
注意:JSX 并不是标准的 JS 语法,是 JS 的语法扩展,浏览器默认是不识别的,脚手架中内置的 @babel/plugin-transform-react-jsx 包,用来解析该语法
2. JSX中使用js表达式
语法
{ JS 表达式 }
1 2 3
| const name = '柴柴'
<h1>你好,我叫{name}</h1> // <h1>你好,我叫柴柴</h1>
|
可以使用的表达式
- 字符串、数值、布尔值、null、undefined、object( [] / {} )
- 1 + 2、’abc’.split(‘’)、[‘a’, ‘b’].join(‘-‘)
- fn()
特别注意
if 语句/ switch-case 语句/ 变量声明语句,这些叫做语句,不是表达式,不能出现在 {} 中!!
3. JSX列表渲染
页面的构建离不开重复的列表结构,比如歌曲列表,商品列表等,我们知道vue中用的是v-for,react这边如何实现呢?
实现:使用数组的map 方法
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| // 来个列表 const songs = [ { id: 1, name: '痴心绝对' }, { id: 2, name: '像我这样的人' }, { id: 3, name: '南山南' } ] function App() { return ( <div className="App"> <ul> { songs.map(item => <li>{item.name}</li>) } </ul> </div> ) } export default App
|
注意点:需要为遍历项添加 key 属性
- key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用
- key 在当前列表中要唯一的字符串或者数值(String/Number)
- 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值
- 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值
4. JSX条件渲染
作用:根据是否满足条件生成HTML结构,比如Loading效果
实现:可以使用 三元运算符 或 逻辑与(&&)运算符
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const flag = true function App() { return ( <div className="App"> {} {flag ? 'react真有趣' : 'vue真有趣'} {} {flag ? <span>this is span</span> : null} </div> ) } export default App
|
5. JSX样式处理
目标任务: 能够在JSX中实现css样式处理
行内样式 - style
1 2 3 4 5 6 7 8 9
| function App() { return ( <div className="App"> <div style={{ color: 'red' }}>this is a div</div> </div> ) }
export default App
|
行内样式 - style - 更优写法
1 2 3 4 5 6 7 8 9 10 11 12 13
| const styleObj = { color:red }
function App() { return ( <div className="App"> <div style={ styleObj }>this is a div</div> </div> ) }
export default App
|
类名 - className(推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| app.css
.title { font-size: 30px; color: blue; } app.js
import './app.css'
function App() { return ( <div className="App"> <div className='title'>this is a div</div> </div> ) } export default App
|
类名 - className - 动态类名控制
1 2 3 4 5 6 7 8 9 10
| import './app.css' const showTitle = true function App() { return ( <div className="App"> <div className={ showTitle ? 'title' : ''}>this is a div</div> </div> ) } export default App
|
官网
参考文档
总结
- 文件名可以是jsx 或者js,不影响文件中的代码
- 组件名称必须大写
- Js中出现 ()代表其中想要写的html
- HTML中出现 {} 代表其中想要写的js
JSX注意事项
JSX必须有一个根节点,如果没有根节点,可以使用<></>(幽灵节点)替代
所有标签必须形成闭合,成对闭合或者自闭合都可以
JSX中的语法更加贴近JS语法,属性名采用驼峰命名法 class -> className for -> htmlFor
JSX支持多行(换行),如果需要换行,需使用() 包裹,防止bug出现
React组件基础
函数式组件
1.函数式组件没有声明周期
2.函数式组件没有this
3.函数式组件没有state状态
函数组件
使用 JS 的函数(或箭头函数)创建的组件,就叫做函数组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 组件定义与渲染
function HelloFn () { return <div>这是我的第一个函数组件!</div> }
function App () { return ( <div className="App"> {} <HelloFn /> <HelloFn></HelloFn> </div> ) } export default App
|
约定说明
- 组件的名称必须首字母大写,react内部会根据这个来判断是组件还是普通的HTML标签
- 函数组件必须有返回值,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null
- 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的返回值就是对应的内容
- 使用函数名称作为组件标签名称,可以成对出现也可以自闭合
类组件
使用 ES6 的 class 创建的组件,叫做类(class)组件
组件定义与渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import React from 'react'
class HelloC extends React.Component { render () { return <div>这是我的第一个类组件!</div> } }
function App () { return ( <div className="App"> {} <HelloC /> <HelloC></HelloC> </div> ) } export default App
|
约定说明
- 类名称也必须以大写字母开头
- 类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
- 类组件必须提供 render 方法render 方法必须有返回值,表示该组件的 UI 结构
事件绑定
- 如何绑定事件
语法
1
| on + 事件名称 = { 事件处理程序 } ,比如:<div onClick={()=>{}}></div>
|
注意点
react事件采用驼峰命名法,比如:onMouseEnter、onFocus
样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function HelloFn () { const clickHandler = () => { console.log('事件被触发了') } return ( <button onClick={clickHandler}>click me!</button> ) }
class HelloC extends React.Component { clickHandler = () => { console.log('事件被触发了') } render () { return ( <button onClick={this.clickHandler}>click me!</button> ) } }
|
- 获取事件对象
通过事件处理程序的参数获取事件对象e
1 2 3 4 5 6 7 8 9 10 11 12
| function HelloFn () { const clickHandler = (e) => { e.preventDefault() console.log('事件被触发了', e) } return ( <a href="http://www.baidu.com/" onClick={clickHandler}>百度</a> ) }
|
组件状态
目标任务: 能够为组件添加状态和修改状态的值
一个前提:在react hook出来之前,函数式组件是没有自己的状态的,所以我们统一通过类组件来讲解
- 初始化状态
通过class的实例属性state来初始化
state的值是一个对象结构,表示一个组件可以有多个数据状态
1 2 3 4 5 6 7 8 9
| class Counter extends React.Component { state = { count: 0 } render() { return <button>计数器</button> } }
|
- 读取状态
通过this.state来获取状态
1 2 3 4 5 6 7 8 9 10
| class Counter extends React.Component { state = { count: 0 } render() { return <button>计数器{this.state.count}</button> } }
|
- 修改状态
this.setState({ 要修改的部分数据 })
setState方法作用
修改state中的数据状态
更新UI
思想
数据驱动视图,也就是只要修改数据状态,那么页面就会自动刷新,无需手动操作dom
注意事项
不要直接修改state中的值,必须通过setState方法进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Counter extends React.Component { state = { count: 0 } setCount = () => { this.setState({ count: this.state.count + 1 }) } render () { return <button onClick={this.setCount}>{this.state.count}</button> } }
|
this问题说明
这里我们作为了解内容,随着js标准的发展,主流的写法已经变成了class fields,无需考虑太多this问题
React的状态不可变
概念:不要直接修改状态的值,而是基于当前状态创建新的状态值
- 错误的直接修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| state = { count : 0, list: [1,2,3], person: { name:'jack', age:18 } } // 直接修改简单类型Number this.state.count++ ++this.state.count this.state.count += 1 this.state.count = 1
// 直接修改数组 this.state.list.push(123) this.state.list.spice(1,1)
// 直接修改对象 this.state.person.name = 'rose'
|
- 基于当前状态创建新值
1 2 3 4 5 6 7 8 9
| this.setState({ count: this.state.count + 1 list: [...this.state.list, 4], person: { ...this.state.person, // 覆盖原来的属性 就可以达到修改对象中属性的目的 name: 'rose' } })
|
表单处理
使用React处理表单元素,一般有俩种方式:
受控组件 (推荐使用)
非受控组件 (了解)
1. 受控表单组件
什么是受控组件? input框自己的状态被React组件状态控制
React组件的状态的地方是在state中,input表单元素也有自己的状态是在value中,React将state与表单元素的值(value)绑定到一起,由state的值来控制表单元素的值,从而保证单一数据源特性
实现步骤
以获取文本框的值为例,受控组件的使用步骤如下:
- 在组件的state中声明一个组件的状态数据
- 将状态数据设置为input标签元素的value属性的值
- 为input添加change事件,在事件处理程序中,通过事件对象e获取到当前文本框的值(即用户当前输入的值)
- 调用setState方法,将文本框的值作为state状态的最新值
代码落地
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import React from 'react'
class InputComponent extends React.Component { state = { message: 'this is message', } changeHandler = (e) => { this.setState({ message: e.target.value }) } render () { return ( <div> {} <input value={this.state.message} onChange={this.changeHandler} /> </div> ) } }
function App () { return ( <div className="App"> <InputComponent /> </div> ) } export default App
|
2. 非受控表单组件
什么是非受控组件?
非受控组件就是通过手动操作dom的方式获取文本框的值,文本框的状态不受react组件的state中的状态控制,直接通过原生dom获取输入框的值
实现步骤
- 导入createRef 函数
- 调用createRef函数,创建一个ref对象,存储到名为msgRef的实例属性中
- 为input添加ref属性,值为msgRef
- 在按钮的事件处理程序中,通过msgRef.current即可拿到input对应的dom元素,而其中msgRef.current.value拿到的就是文本框的值
代码落地
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import React, { createRef } from 'react'
class InputComponent extends React.Component { msgRef = createRef()
changeHandler = () => { console.log(this.msgRef.current.value) }
render() { return ( <div> {} <input ref={this.msgRef} /> <button onClick={this.changeHandler}>click</button> </div> ) } } function App () { return ( <div className="App"> <InputComponent /> </div> ) } export default App
|
参考文档
gitee
官方文档