博客笔记来自于学习 柴柴老师在b站分享的react学习视频,仅供学习参考,学习视频是来自于b站的:柴柴_前端教书匠,视频链接:React入门到实战(2022全网最新)_哔哩哔哩_bilibili
和 react官网 开始 – React (docschina.org)
目录
jsx语法
jsx表达式案例
jsx条件渲染
jsx中的样式处理
函数组件的创建和渲染
组件与props
函数事件绑定
在事件中传递自定义参数
props只读性
箭头函数的写法可以解决this指向
解构赋值
useState
useEffect
jsx语法
jsx表达式案例
语法:{ JS 表达式 } 注意这个{}里面只能写表达式,不能写语句!!!
可以使用的表达式:
-
字符串、数值、布尔值、null、undefined、object( [] / {} )
-
1 + 2、'abc'.split('')、['a', 'b'].join('-')
-
fn()
案例:
//1.识别我们的常规变量
const name = "react 学习"
//2.原生js中的调用
const getAge = () =>{
return "永远的18";
}
//3.三元运算符(常用)
const flag = false;
function App() {
return (
<div className="App">
{name}<br></br>
{getAge()}<br></br>
{flag ? '18':'68'}
</div>
);
}
export default App;
jsx条件渲染
作用:根据是否满足条件生成HTML结构,满足条件才进行渲染。
实现:可以使用 三元运算符
或 逻辑与(&&)运算符
// 来个布尔值
const flag = true
function App() {
return (
<div className="App">
{/* 条件渲染字符串 */}
{flag ? 'react真有趣' : 'vue真有趣'}
{/* 条件渲染标签/组件 */}
{flag ? (<span>this is span</span>) : null}
</div>
)
}
export default App
如果我们遇到了 复杂的多分支的逻辑,那么应该怎么办呢?肯定是不能三元套三元的,这样会导致代码的可读性非常弱。
原则:模板中的逻辑尽量保持精简。 收敛为一个函数,通过一个专门的函数来写分支逻辑,模板中只负责调用。
const getTag = (type)=>{
if(type === 1){
return <h1>this h1</h1>
}
if(type === 2){
return <h2>this h2</h2>
}
if(type === 3){
return <h3>this h1</h3>
}
}
function App() {
return (
<div className="App">
getTag(1)
</div>
);
}
export default App;
jsx中的样式处理
注意:使用样式处理的时候,需要使用两个{}来进行包裹,第一个{}的作用是为了让第二个{}识别为对象,第二个{}是对象,用来写我们的样式属性。
1、行内样式 - style (在元素身上绑定一个style属性即可)
function App() {
return (
<div className="App">
<div style={{ color: 'red' }}>this is a div</div> //所以以后看见两个{}要知道是在干啥
</div>
)
}
export default App
2、行内式 - style - 更优写法 (把样式以对象抽离出来)
const styleObj = {
color:red
}
function App() {
return (
<div className="App">
<div style={ styleObj }>this is a div</div>
</div>
)
}
export default App
3、类名 - className(推荐)(在元素身上绑定一个className属性即可)
.active{
color:blue;
}
import './app.css'
function App() {
return (
<div className="App">
<span className='active'>测试类名样式</span>
</div>
)
}
export default App
函数组件的创建和渲染
组件与props
组件:组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。
先看一个react官网给的案例:下面的代码会输出:Hello Sara
function Welcome(props) { //自定义组件
return <h1>Hello, {props.name}</h1>;
}
//如果是类组件 那么使用this来获取
//class Square extends React.Component {
// render() {
// return (
// <button className="square">
// {this.props.name}
// </button>
// );
// }
//}
const element = <Welcome name="Sara" />; //在jsx中使用自定义组件 Welcome,并且传了一个属性name给Welcome组件,Welcome组件可以用props来接收使用Welcome组件的jsx中传过来的属性或者是对象
ReactDOM.render(
element,
document.getElementById('root')
);
让我们来看看这个例子中发生了什么:
-
我们调用
ReactDOM.render()
函数,并传入<Welcome name="Sara" />
作为参数。 -
React 调用
Welcome
组件,并将{name: 'Sara'}
作为 props 传入。 -
Welcome
组件将<h1>Hello, Sara</h1>
元素作为返回值。 -
React DOM 将 DOM 高效地更新为
<h1>Hello, Sara</h1>
。
约定说明
-
组件的名称必须首字母大写,react内部会根据这个来判断是组件还是普通的HTML标签。
-
函数组件必须有返回值,返回的值表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null。
-
组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的返回值就是对应的内容。
-
使用函数名称作为组件标签名称,可以成对出现也可以自闭合。
import React from "react"
//创建函数式组件
function Hello () {
return <div>hello</div>
}
//类组件的创建和渲染
class HelloCompoent extends React.Component {
//这个render函数是必须的
render () {
return <div>this is class component</div>
}
}
function App () {
return (
<div className="App">
{/* 渲染hello组件 */}
<Hello></Hello>
{/* 渲染类组件 */}
<HelloCompoent></HelloCompoent>
</div>
)
}
export default App
函数事件绑定
-
语法 on + 事件名称 = { 事件处理程序(回调函数) } ,比如:
<div onClick={ onClick }></div>
-
注意点 react事件采用驼峰命名法,比如:onMouseEnter、onFocus
函数事件绑定:
import React from "react"
//创建函数式组件
function Hello () {
//创建一个事件(相当于一个方法) 这种类似java的lambada表达式的写法是react中声明事件的标准写法,可以避免一些不必要this指向问题
const clickHandler = () => {
console.log('函数组件中的事件被触发了')
}
//绑定事件
return <div onClick={clickHandler}>hello</div>
}
function App () {
return (
<div className="App">
{/* 渲染hello组件 */}
<Hello></Hello>
</div>
)
}
export default App
在事件中传递自定义参数
场景:就是我们想在触发事件的时候,传递一些自定义参数,应该怎么操作?
import React from "react"
//创建函数式组件
function Hello () {
//创建一个事件(相当于一个方法)
const clickHandler = (msg) => {
console.log('函数组件中的事件被触发了', msg)
}
//需要在调用的时候传递实参,需要修改函数组件触发的调用方式了 : 改造成箭头函数的调用方式就行
return <div onClick={()=>clickHandler('this is msg')}> 点击 </div>
{/*之前的调用方式<div onClick={clickHandler}>点击</div> */}
}
function App () {
return (
<div className="App">
{/* 渲染hello组件 */}
<Hello></Hello>
</div>
)
}
export default App
如果我们想要既传递 e 又要想要传递自定义参数,那么应该怎么操作?
import React from "react"
//创建函数式组件
function Hello () {
//创建一个事件(相当于一个方法)
const clickHandler = (e,msg) => {
console.log('函数组件中的事件被触发了', e,msg)
}
//需要在调用的时候传递实参,需要修改函数组件触发的调用方式了 : 改造成箭头函数的调用方式就行 并且需要注意形参和实参的顺序
return <div onClick={(e)=>clickHandler(e,'this is msg')}> 点击 </div> {/* 需要先捕获e然后再传递到绑定的事件中*/}
{/*
之前不需要传递参数的调用方式<div onClick={clickHandler}>点击</div>
之前传递一个自定义参数的调用方式:return <div onClick={()=>clickHandler('this is msg')}> 点击 </div>
*/}
}
function App () {
return (
<div className="App">
{/* 渲染hello组件 */}
<Hello></Hello>
</div>
)
}
export default App
总结:
1、只需要一个额外参数 写法: {clickHandler} -> { () => clickHandler('自定义参数')}
2、既需要e也需要额外的自定义参数 {(e) => clickHandler(e,'自定义的参数') }
props只读性
在 组件与props中 我们已经简单的说明了一下props的作用,这里单独的来介绍一下props的只读性。
组件无论是使用 函数声明还是通过class 声明 ,都决不能修改自身的 props。
function sum(a, b) {
return a + b;
}
这样的函数被称为“纯函数”,因为该函数【不会尝试更改入参】,且多次调用下相同的入参始终返回相同的结果。
相反,下面这个函数则不是纯函数,因为它更改了自己的入参:
function withdraw(account, amount) { //account中的total属性被更改了
account.total -= amount;
}
所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
在不违反上述规则的情况下,state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容。
箭头函数的写法可以解决this指向
import React from "react"
class Test extends React.Component {
change(){
console.log(this) //输出的this是组件的实例属性
}
render () {
return (
<div>
{/*如果不通过constructor做修正,那么我们可以直接在事件绑定的位置通过箭头函数的写法 --> 这种写法是直接沿用父函数(render)中的this 这个函数的父函数是render,这也说明了render中的this指向的就是【当前组件】的实例对象(react内部进行了修正) */}
<button onClick={()=>this.change()}>click</button>
</div>
)
}
}
function App () {
return (
<div className="App">
{/* 渲染定义的类组件 */}
<Test></Test>
</div>
)
}
export default App
建议:在开发中定义函数式组件的时候直接就 handle = () => {} 来定义就行,然后引用的时候直接通过 this.handle来使用。
解构赋值
参考来源:解构赋值 - JavaScript | MDN (mozilla.org)
解构赋值:可以将数组中的值或对象的属性取出,赋值给我们新声明的变量。
-
var定义变量,没有块的概念,可以跨块访问,不能跨函数访问,不初始化出现undefined,不会报错
-
let定义变量,只能在块作用域里访问,也不能跨函数访问,对函数外部无影响。
-
const定义常量,只能在块作用域里访问,也不能跨函数访问,使用时必须初始化(即必须赋值),而且不能修改。
先看基础使用的案例:
// 数组的解构 会按照变量的顺序进行解构
const x = [1, 2, 3, 4, 5];
const [y, z] = x;
console.log(y); // 1
console.log(z); // 2
const foo = ['one', 'two', 'three'];
const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
//解构对象中的属性 对象中的
const obj = { a: 1, b: 2 };
const { a, b } = obj;
// 相当于下面的赋值写法
// const a = obj.a;
// const b = obj.b;
const obj2 = { x:"你好", c: 2 };
const { x, c } = obj2;
console.log(x) //你好
console.log(c) //2
//报错
const obj3 = { "你好", d: 2 };
const { x, c } = obj3;
console.log(x)
console.log(d)
const obj4 = { x:"你好", e: 2 };
const { ddddd, e } = obj4;
console.log(ddddd) // undefined
console.log(e) //2
//如果想把属性赋值给新的变量名 那么应该怎么操作?
const obj4 = { x:"你好", e: 2 };
const { x:ddddd, e } = obj4;
console.log(ddddd) // 你好
console.log(e) //2
组合对象与数组的解构赋值:案例:想要下面 props
数组中的第三个元素,同时只需要对象中的 name
属性
const props = [
{ id: 1, name: 'a'},
{ id: 2, name: 'b'},
{ id: 3, name: 'c'}
];
const [,, { name }] = props;
console.log(name); // "c"
默认值:每个解构属性都可以有一个默认值。当属性不存在或值为 undefined
时,将使用默认值。如果属性的值为 null
,则不使用它。
const [a = 1] = []; // a 是 1
const { b = 2 } = { b: undefined }; // b 是 2
const { c = 2 } = { c: null }; // c 是 null
剩余属性:你可以使用剩余属性(...rest
)结束解构模式。此模式会将对象或数组的所有剩余属性存储到新的对象或数组中。(用的挺多的)
const { a, ...others } = { a: 1, b: 2, c: 3 };
console.log(others); // { b: 2, c: 3 }
const [first, ...others2] = [1, 2, 3];
console.log(others2); // [2, 3]
useState
案例演示:
// userState()就是我们使用的函数,我们可以在()中传一个初始值,这个初始值会被赋值给你声明的变量count,如果你想在其他地方修改这个count,那么可以调用声明的setCount()方法 并且把新的count值传到这个()中 setCount(newCount)
const [count, setCount] = useState(0); // 参数:状态初始值比如,传入 0 表示该状态的初始值为 0,返回值:数组,包含两个值:第一个是表示:状态值(state) 第二个是表示:修改该状态的函数(setState)
import { useState } from 'react'
function App() {
// 参数:状态初始值比如,传入 0 表示该状态的初始值为 0
// 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)
const [count, setCount] = useState(0)
return (
<button onClick={() => { setCount(count + 1) }}>{count}</button>
)
}
export default App
状态的读取和修改:
-
读取状态:该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用
-
修改状态
-
setCount是一个函数,参数表示
最新的状态值
-
调用该函数后,将使用新值替换旧值
-
修改状态后,由于状态发生变化,会引起视图变化
注意:
-
修改状态的时候,一定要使用新的状态替换旧的状态,不能直接修改旧的状态,尤其是引用类型
-
useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值
-
-
import { useState } from 'react'
function App() {
const [count, setCount] = useState(0)
// 在这里可以进行打印测试
console.log(count)
return (
<button onClick={() => { setCount(count + 1) }}>{count}</button>
)
}
export default App
useState
注意事项 :
-
只能出现在函数组件或者其他hook函数中
-
不能嵌套在if/for/其它函数中(react按照hooks的调用顺序识别每一个hook)
let num = 1
function List(){
num++
if(num / 2 === 0){
const [name, setName] = useState('cp')
}
const [list,setList] = useState([])
}
// 俩个hook的顺序不是固定的,这是不可以的!!!
useEffect
什么是副作用:一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用
常见的副作用
-
数据请求 ajax发送
-
手动修改dom
-
localstorage操作
使用步骤
-
导入
useEffect
函数 -
调用
useEffect
函数,并传入回调函数 -
在回调函数中编写副作用处理(dom操作)
-
修改数据状态 (配合useState中的set方法一起使用)
-
检测副作用是否生效
import { useEffect, useState } from 'react'
function App() {
const [count, setCount] = useState(0)
// useEffect() 调用副作用函数 ()=>{} 回调函数
useEffect(()=>{
// dom操作 进行操作
document.title = `当前已点击了${count}次`
})
return (
<button onClick={() => { setCount(count + 1) }}>{count}</button>
)
}
export default App