react 学习笔记 李立超老师 | (学习中~)

文章目录

  • react学习笔记01
    • 入门
      • 概述
      • React 基础案例HelloWorld
        • 三个API介绍
      • JSX
        • JSX 解构数组
      • 创建react项目(手动)
      • 创建React项目(自动) | create-react-app
      • 事件处理
      • React中的CSS样式
        • 内联样式 | 内联样式中使用state (不建议使用)
        • 外部样式表 | CSS Module
    • React组件
      • 函数式组件和类组件
        • 生成一组标签/组件
      • props 父组件给子组件传属性/方法
        • 给组件设置className样式不生效
      • state 维护组件的响应式状态
        • useState(stateInitValue)
      • Ref 获取DOM对象
      • 非受控组件与受控组件
        • 数据的双向绑定
        • 子组件给父组件传值 = props传递函数 + 子组件调用函数
        • vue中v-if与v-show的React写法
        • Portal 将元素渲染到指定位置
      • Fragment 组件
      • Context 祖先组件向子孙组件传值

react学习笔记01

学习视频 react18 李立超

学习中get到的新用法

  1. Date类的toLocalString方法,可以更为灵活的处理Date类。

  2. 标签属性中闭包的使用
    举例:仅在删除状态时使用id,不需要单独传递id属性。

    const logItemDate = logsData.map(item=> <LogItem  onDelLog ={()=> delLog(item.id)}>)
    
  3. 移动端适配 rem + vw
    可以使用vw获取视口宽度,将font-size设置单位为vw,然后结合rem做适配。
    1vw = 视口宽度的1% -> 100vw = 视口的宽度

    一般设置html的font-size值 = 屏幕宽度/设计稿宽度,但移动端比如375px计算出的font-size值小于12px会造成一些错误和奇怪的问题,因此把比例扩大100倍

    为了使比例不变,相应的设计图元素使用时设计图元素大小/100 rem

    根html的font-size值 = 屏幕宽度/设计稿宽度*100 
    font-size = 100vw/设计稿宽度*100
    

入门

概述

AJAX+DOM可以实现网页的局部刷新,但是新数据不能直接在网页中显示,需要通过DOM将数据转换为网页中的节点。

react帮助我们根据不同的数据来快速构建用户项目,同时在构建过程中确保其流畅度。

react特点

1.使用虚拟DOM而不是真正的DOM

2.声明式编码(声明式:结果为导向,不关心结果 命令式:一行代码一个命令)

3.支持服务器端渲染

React 基础案例HelloWorld

入门案例采用外部引入脚本使用(正常开发使用包管理器)

  • react.development.js reactreact核心库,只要使用react就必须要引入。下载地址
  • react-dom.development.js react-domreactdom包,使用react开发web应用时必须引入。下载地址
  • babel.min.js 浏览器不能识别JSX,利用该babelJSX转换为JS代码。下载地址

1.引入脚本

<script src="../script/react.development.js"></script>
<script src="../script/react-dom.development.js"></script>

2.创建一个React元素

React.createElement(组件名/元素名,元素中的属性,元素的子元素/内容)

const reactDiv = React.createElement('div',{},'我是react创建的div'); 

3.获取根元素对应的React元素

ReactDOM.createRoot(Dom元素);

// html
<div id="root"></div>
// js
const root = ReactDOM.createRoot(document.getElementById('root'));

4.将reactDiv渲染到React根元素中

root.render(reactDiv)
三个API介绍
  • React.createElement(type,[props],[...children]) 用来创建React元素(并不是ReactDom,所以这里使用React调用)

    • class属性需要使用className属性代替。

    • type如果是标签名(元素)需要全小写,首写母大写会被认为是组件

    • 在设置属性时,事件名应遵守驼峰命名法,事件值需要是一个函数,不能是console.log(xx)这种表达式。如果直接写一个函数调用语句,则在绑定事件时就会被调用(之后事件不会被触发)

    • React元素是一次性的,一旦创建就无法修改,只能使用新创建的元素进行替代

  • ReactDOM.createRoot(container[,options]);用来创建React的根容器,根容器用来放置React元素

    • 将参数的DOM元素转换为React根元素
  • ReactDOM实例.render(ReactElement)React元素渲染到根元素中

    • DOM根元素中所有的内容都会被删除(不会修改DOM根元素本身),被React元素转换而成的DOM元素替换
    • 重复调用render(),React会将两次虚拟DOM进行对比,确保只修改发生变化的元素,对DOM做最少修改。首次调用时,容器节点里的所有DOM都会被替换,后续的调用则会使用ReactDOM差分算法(diff)进行更新

JSX

上述方法中React.createElement('button', {}, '我是按钮')还是命令式编码方法,告诉reactcreateElement去创建一个button按钮,该按钮没有属性,内容为我是按钮。

声明式编程结果导向,告诉结果,不关系过程怎么样。

const button = <button>我是按钮</button>; // 告诉react我需要一个button按钮元素,不关心react如何创建

React中可以通过JSXJavaScript Syntax Extension)来创建React元素,JSX 让我们以类似于HTML 的形式去使用 JSJSXReact中声明式编程的体现方式。

JSX需要被翻译为JS代码,才能被React执行。 要在React中使用JSX,必须引入babel来完成“翻译”工作。

  • JSX就是React.createElement()的语法糖,最终都会转换为以调用React.createElement()创建元素的代码。

  • JSX在执行之前都会被babel转换为JS代码

    <!-- 引入babel -->
    <script src="script/babel.min.js"></script>
    <!--设置js代码被babel处理-->
    <script type="text/babel">
        const div = <div>
            我是一个div
            <button>我是按钮</button>
        </div>;
     	const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(div);    
    </script>
    
  • JSX不是字符串,不需要加引号

const div =  <div>我是一个div</div>  // 正确写法   
  • JSXhtml标签应该小写开头,React组件应该大写开头
<div> // 小写html标签
<Div> // 大写组件
  • JSX有且只有一个根标签

  • JSX的标签必须正常结束(自结束标签必须写/)

const input = <input type="text" / >
  • JSX中使用{}嵌入表达式(有值的语句就是表达式)
const name = "ranran"
const div = <div>{name}</div> // 才会显示ranran,没有括号会把name识别为字符串
  • 如果表达式值为空值、布尔值、undefined,将不会显示

  • JSX属性可以直接在标签中设置

    • 事件绑定需要是一个函数,而不能直接是函数调用(绑定时就会被触发,不会延迟触发)
    • className代替class
    • style必须使用对象设置,属性名必须用驼峰命名法
const div = <div onClick="()=>{console.log('ranran')}" 
 style={{backgroundColor: "yellowgreen", border: '10px red solid'}}
></div> // 外面的大括号表示style必须使用对象设置,里面的对象表示给他设置的值是一个对象(有多个样式)
  • 在语句中可以操作JSX

    const name = 'ranran';
    const lang = 'cn';
    
    let div;
    if(lang === 'en'){
        div = <div>hello {name}</div>;
    }else if(lang === 'cn'){
        div = <div>你好 {name}</div>;
    }
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(div)
    
JSX 解构数组

JSX在解构{}的内容时,如果内容是数组则会自动将其展开。

//页面:孙悟空猪八戒沙和尚
const data = ['孙悟空', '猪八戒', '沙和尚'];
const div = <div>{data}</div> 
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(div)

/*
· 孙悟空
· 猪八戒
· 沙和尚
*/
const data = ['孙悟空', '猪八戒', '沙和尚'];
const list = <ul>{data.map(item => <li>{item}</li>)}</ul>;
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(list)//页面:孙悟空猪八戒沙和尚
const data = ['孙悟空', '猪八戒', '沙和尚'];
const div = <div>{data}</div> 
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(div)

/*
· 孙悟空
· 猪八戒
· 沙和尚
*/
const data = ['孙悟空', '猪八戒', '沙和尚'];
const list = <ul>{data.map(item => <li>{item}</li>)}</ul>;
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(list)

React通过虚拟DOMReact元素和原生DOM元素进行映射

当我们调用root.render时。页面就会发生重新渲染
React通过diff算法将新的虚拟DOM和旧的比较,找到发生变化的元素,并且只对变化的元素进行修改。

数组中(当前数组)每一个元素都需要设置一个唯一key
重新渲染页面时,Reactkey值会比较key值相同的元素,没key值会按照顺序进行比较。

  1. 开发中一般会采用数据的 id 作为 key
  2. 尽量不使用元素的 index 作为 key 索引会跟着元素顺序的改变而改变,所以使用索引做 key 跟没有 key 是一样的。 唯一的不同就是,控制台的警告没了。 当元素的顺序不会发生变化时,用索引做 key 也没有什么问题。
const data = ['孙悟空', '猪八戒', '沙和尚'];
const list = <ul>{data.map(item => <li key={ item }>{ item }</li>)}</ul>;
// const list = <ul>{data.map((item,index) => <li key={ index }>{ item }</li>)}</ul>;
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(list)

创建react项目(手动)

React官方为了方便开发,提供react-scripts包(①打包②测试服务器-根据代码变化自动刷新避免改一点就重新打包),包中提供了项目开发中的大部分依赖。
由于提供了配置好的工具,我们一些操作就要符合约定。

使用包管理器管理项目,没有办法直接放在网页中运行。需要经过webpack打包,才能在浏览器中正常执行。

  1. 创建React
根目录
    - public(可以web直接访问的文件,不用打包就可以浏览器访问的静态资源)
        - index.html (入口文件,必须有,首页模板打包时以此为模板生成最终的index/html | 添加标签 <div id="root"></div>- src(源码,JS源代码)
        - index.js(必须,webpack打包文件的入口,该文件会被自动引入public/index.html中)
  1. pnpm init 初始化项目,生成package.json文件(大部分时候这一步可以省略)
  2. pnpm install react react-dom react-scripts 安装项目依赖
  3. 编写代码src/index.js
// 引入ReactDOM
import ReactDOM from 'react-dom/client';

// 创建一个JSX
const APP = <div><h1>这是一个react项目</h1></div>

// 获取一个根元素
const root = ReactDOM.createRoot(document.getElementById('root'));
// 将APP渲染进根容器
root.render(APP);
  1. 运行项目
  • pnpm react-scripts build 打包项目,一般开发完成之后需要上线时使用该命令进行打包。
    初次需要输入y确认。打包时需要默认配置,会询问是否添加默认配置。

在这里插入图片描述

正常情况,右键打开会报错。因为打包好的文件需要部署在服务器上运行,而不是直接使用浏览器打开。每次打包后路径都是这样需要手动修改。

在这里插入图片描述

  • pnpm react-scripts start 开发中使用的命令
    通过webpack启动内部的测试服务器,可以实时对更新代码进行编译。这个命令太长,可以在package.jsonscripts 选项中配置命令,下次可以使用命令pnpm start

    "scripts": {
      	"start": "react-scripts start"
    }
    

react 一定需要两个文件

  • public/index.html:入口文件,首页模板打包时以此为模板生成最终的index/html - 提供dom root根节点
  • src/index.jswebpack打包文件的入口,该文件会被自动引入public/index.html中 - 将root转化为react根节点元素后,将react元素挂载到react根节点中

创建React项目(自动) | create-react-app

命令:npx create-react-app 项目名

除了public/index.htmlsrc/index.js必须保留外,其他的东西都是可以删除的。

/*
  reate-react-app 创建index.js
  其中<React.StrictMode>使用严格模式渲染React元素 - 可以不使用
*/
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    aaa
  </React.StrictMode>
);


事件处理

react 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。

  • 使用 JSX 语法时需要传入一个函数作为事件处理函数。事件绑定需要是一个函数,而不能直接是函数调用(绑定时就会被触发,不会延迟触发,等于将函数的返回值给了该事件)

    // 传统 HTML
    <button onclick="activateLasers()">
      Activate Lasers
    </button>
    // React
    <button onClick={activateLasers}>  
       Activate Lasers
    </button>
    
  • React事件通过会传递事件对象event,但其不同于原生的事件对象,是React包装后的事件对象,该对象已经处理了跨浏览器的兼容性问题。

    React中事件回调函数不能通过返回false阻止默认行为,必须显式地使用event事件对象的preventDefault方法

    // 传统 HTML
    
    <form οnsubmit="console.log('You clicked submit.'); return false">
      <button type="submit">Submit</button>
    </form>
    
    // React
    function Form() {
      function handleSubmit(e) {
        e.preventDefault();    
        console.log('You clicked submit.');
      }
    
      return (
        <form onSubmit={handleSubmit}>
          <button type="submit">Submit</button>
        </form>
      );
    }
    

React中的CSS样式

内联样式 | 内联样式中使用state (不建议使用)

style必须使用对象设置,属性名必须用驼峰命名法

const StyleDemo = () => {
    return (
        <div style={{color:'red', backgroundColor:'#bfa', fontSize:20, borderRadius:12}}>
            我是Div
        </div>
    );
};

export default StyleDemo;

当样式过多,JSX会比较混乱,可以使用变量去保存对象

import React from 'react';

const StyleDemo = () => {
    const divStyle = {color: 'red', backgroundColor: '#bfa', fontSize: 20, borderRadius: 12}

    return (
        <div style={divStyle}>
            我是Div
        </div>
    );
};

export default StyleDemo;

内联样式中使用state
当样式是动态时,可以在样式中使用state变量。

import React, {useState} from 'react';

const StyleDemo = () => {

    const [showBorder, setShowBorder] = useState(false);

    const divStyle = {
        color: 'red',
        backgroundColor: '#bfa',
        fontSize: 20,
        borderRadius: 12,
        border: showBorder?'2px red solid':'none'
    };

    const toggleBorderHandler = ()=> {
      setShowBorder(prevState => !prevState);
    };

    return (
        <div style={divStyle}>
            我是Div
            <button onClick={toggleBorderHandler}>切换边框</button>
        </div>
    );
};

export default StyleDemo;
外部样式表 | CSS Module

外部样式是指将样式编写到外部的css文件中,直接通过import引用。

直接import引入的样式都是全局样式,其他组件也看得见这个样式。如果不同的样式表中出现了相同的类名,会出现相互覆盖情况。

import './index.css'

CSS Module
使用CSS Module后,网页中元素的类名会自动计算生成并确保唯一

如果引用同一个模块,计算出来的类名是相同的。

CSS ModuleReact中已经默认支持(前提是使用了react-script)

  1. 文件样式的文件名为xxx.module.css
  2. 在组件中引入样式的格式为import xxx from './xxx.module.css'
  3. 设置类名时通过xxx.yyy的形式来设置
/*
StyleDemo.module.css
*/
.myDiv{
    color: red;
    background-color: #bfa;
    font-size: 20px;
    border-radius: 12px;
}

/*
StyleDemo.js
*/
import Styles from './StyleDemo.module.css';

const StyleDemo = () => {
    return (
        <div className={Styles.myDiv}>
            我是Div
        </div>
    );
};

export default StyleDemo;

React组件

组件需要遵守的规则

  • 组件名首字母必须大小(小写字母开头的组件会被视为原生DOM标签)
  • 组件中只能有一个根元素

函数式组件和类组件

React中定义组件有两种方式

  • 基于函数的组件 - 函数式组件(推荐) :函数组件是返回JSX普通函数
  • 基于类的组件 - 类组件

函数式组件

函数组件是返回JSX普通函数

//1.创建函数式组件 App.js
const App = () => {
  return <div>我是App组件!</div>
};
// 2.导出App
export default App;


// index.js
// 3.引入App
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById('root'));
// 4.React组件可以直接通过JSX渲染
root.render(<App/>);	//root.render(App()); 也可以,只是<App/>内部做了更多的事情。

类组件

1.创建一个ES6 class,并继承于React.Component

2.添加一个render方法,方法的返回值为JSX

import React from "react"
//1.创建类组件  必须要继承React.Component
class App extends React.Component{
    constructor(props){ // 参数props接受父组件的传值
        this.state = 'xxx' //state的使用
    }
    // 2.添加render方法
    render(){
        return <div>我是一个类组件{this.props}</div>
    }
}

// index.js
// 3.引入App
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById('root'));
// 4.React组件可以直接通过JSX渲染
root.render(<App/>);	//root.render(App()); 也可以,只是<App/>内部做了更多的事情。

props、state、ref

  • 类组件的props存储在类的实例对象中,可以通过this.props访问。

  • 类组件中state统一存储到了实例对象的state属性中,可以通过this.state来访问,通过this.setState()修改。

    • 通过this.setState修改state,只修改设置了state的属性,并不会修改没设置的第一层属性。
  • 通过React.createRef()(函数式为useRef)创建属性存储DOM对象,同样通过对象.current获取

  • 事件回调函数需要定义为类的方法,建议使用箭头函数,这样this指向的是react实例。否则函数里的this会执行设置事件的dom元素

import React,{ Component } from 'react'

class App extends Component{
 	state = {
        count:0,
        age:{} 
    }  
    divRef = React.createRef();
    // 事件回调函数需要定义为类的方法,建议使用箭头函数,这样this指向的是react实例。否则函数里的this会执行设置事件的dom元素
    clickHandler = ()=>{
        // 写法1:this.setState({count:this.state.count+1})
        // 写法2
        this.setState(prevCount => {
            return {
                count:prevCount+1;
            }
        })
    }
    retnder(){
        return <div>
            <h1 ref={ divRef }>this.props<h1>
            <h1 @onClick={this.clickHandler}>this.state.count<h1>   
        </div>
    }
}
生成一组标签/组件

react中对于根据数组数据产生一组标签或者一组组件,没有类似vuev-for指令,一般使用{ data.map(JSX) }的语法进行生成。

const App= () => {
	const data = [{title:"1",id:"0"},{title:"2",id:"1"},{title:"3",id:"2"}];
    return <div>
    { data.map(item => <Button key={item.id} titile={item.title}></Button >) }
    </div> 
    
    /*
     写法1 
     return <div> { data.map(item => <Button key={item.id} titile={item.title} />) }  </div> 
    写法2:将对象的每个属性都传递
    return <div> { data.map(item => <Button {...item}>) </div>
	}
    */
};

export default App;

props 父组件给子组件传属性/方法

父组件通过使用子组件时,定义自定义参数传递属性/方法。子组件通过参数props接收(函数式组件的第一个参数)。
react中的props类似vue中的props是只读属性是无法修改的

props.children中可以获取到父组件中,子组件标签体内部的值。

// 父组件
<Button bgColor='red' color={ color }>我是一个按钮</Button>

//子组件
const Button = (props) => {
    return <button style={{backgroundColor:props.bgColor, color:props.color}}>{props.children}</button>;
};

export default Button;
给组件设置className样式不生效

原因

className会被认为是一个属性传递给子组件,需要在子组件的根元素使用className={props.className}接收。

state 维护组件的响应式状态

React中,当组件渲染完毕后,再修改组件中的变量,不会使组件重新渲染。state相当于一个变量,只不过在React中进行了注册。React会监控整个变量的变化,当state发生变化时,会自动触发组件的重新渲染。

页面的渲染靠的是render函数

state概述

stateprops类似,都是一种存储属性的方式。

  • state只属于当前组件(组件的私有属性),其他组件无法使用。
  • state的值是对象,当其内容发生变化相关组件会一起刷新
useState(stateInitValue)

通过钩子函数useState(stateInitValue)创建stateReact中钩子函数只能用于函数组件或自定义钩子。

  • 参数是整个state变量的初始值
  • 函数返回一个数组[stateVariable,setStateFunction],第一个元素是state变量的初始值(只用于显示),第二个元素是修改该变量的函数(函数的参数为新值)。调用修改函数修改state变量的值(state值发生变化)会触发组件的重新渲染,直接修改state变量不会触发组件的重新渲染。
import { useState } from 'React'

const [stateVariable,setStateFunction] = useState(1);

注意点

  1. state值是一个对象时,setState()修改时,使用新的对象去替换已有对象。
const [user, setUser] = useState({name:"ranran",age:18})
user.name = "xxx"; 
serUser(user); // user是对象,对象的地址没有发生变化,所以不会引起组件重新渲染

/* 
解决方案:将其拷贝给另一个新对象,修改新对象的属性
*/
setUser({...user,name:"xxx"}) // 后面的name会覆盖前面的name
  1. 通过setState()去修改一个state时,并不表示修改当前的state,修改的是组件下一次渲染的state

  2. setState()会触发组件的异步渲染(并不是马上调用就渲染,放入事件循环队列中等待执行),所以当调用setState()需要使用state值时,可能出现计算错误。

    因为setState()修改的是下一次渲染的state,如果下一次渲染还没进行前又调用了setState(),此时state还是旧值,所以就会出现计算错误。

    解决办法 : 通过传递回调函数的形式修改state

    回调函数的返回值会成为新的state值,回调函数执行时React会将最新的state值作为参数传递。

    setCount(state => state+1); // 传递参数,React会保证参数的state是最新值
    

如果setState()中需要用到旧值,参数都采用函数的形式。

Ref 获取DOM对象

Refreference的简写,用来获取真实DOM的引用。

  • 使用useRef()钩子函数获取DOM对象
    • 1.通过useRef()钩子函数返回一个普通JS对象,React会自动将DOM对象传递到该对象的current属性中。
    • 2.被引用的DOM元素上添加ref属性,值为上述的对象。
      根据描述,直接创建一个有current属性的普通JS对象可以实现相同的效果。

两种方法的不同点

  • 自定义对象方法,组件每次重新渲染,都会创建一个新对象
  • 使用useRef()函数返回的对象的声明周期和组件的声明周期一致,所以每次重新渲染,该ref对象都是原来的。
import {useRef} from 'react';

const MyComponent = () => {

    const divRef = useRef();
	/*
	const divRef = {current:null}
    */
    const clickHandler = () => {
        console.log(divRef);
    };

    return (
            <div ref={divRef} onClick={clickHandler}>一个div</div>      
    );
};

export default MyComponent;

非受控组件与受控组件

非受控组件:表单中的数据来源于用户填写的组件,表单元素的值不会更新state,输入数据都是现用现取的。

受控组件:使 Reactstate 成为唯一数据源,由state控制表单。

数据的双向绑定

将表单的value绑定为state数据,表单的onChange事件触发时,通过事件对象event获取到新值,然后使用setState修改state的值为新值。

import { useState } from 'react';
import './index.css';

const Demo = () => {
    // 如果有多个表单,可以将表单数据设置为一个对象
    const [inputValue, setInputValue] = useState('');
    return (
        <>
            <input
                type="text"
                className="inputDemo"
                value={inputValue}
                onChange={e => {
                    setInputValue(e.target.value);
                }}
            />
        </>
    );
};

export default Demo;
子组件给父组件传值 = props传递函数 + 子组件调用函数
  1. 在父组件中,使用props给子组件传递一个自定义事件
  2. 在子组件中将需要传递的数据作为函数参数,调用函数
// 父组件
<LogsItem onSavaLog={ savaLogHandler }>

// 子组件
const LogsItem = (props) => {
	props.savaLogHandler("需要传递的数据");
}

关于传递setState函数给子组件的一些说法:尽量不要这样做,state在哪里,setState尽量就在哪里。

vue中v-if与v-show的React写法
  • v-if-v-else配对出现 可以使用条件判断
  • v-show/仅有v-if 可以使用&&
// v-if/v-else 可以使用条件判断
控制变量 ? v-if显示的 : v-else显示的

// v-show/仅有v-if 可以使用&& 
控制变量 && v-show显示的

如果显示出来的组件内部需要修改外部的控制变量,react中一般的做法时将函数作为参数传递。因为控制变量在外部,内部只需要调用该函数,外部修改控制变量的值。

Portal 将元素渲染到指定位置

React中,父组件引入子组件后,子组件会直接在父组件内部渲染。换句话说,React元素中的子组件,在DOM中,也会是其父组件对应DOM的后代元素。

问题描述
每个组件都是相同的构成(想象成一个列表),组件内部包含一个子组件,该子组件的作用是生成一个遮罩覆盖全局。
组件1开启相对定位,遮罩开启固定定位(不一定是和这个例子相同的定位方式,这里举例)
由于组件1组件2组件3的 z-index:1,后面的组件会覆盖前面的。所以组件1中的遮罩出现时,覆盖不了组件2组件3,即使遮罩的z-index:999(理解为在组件1内部元素的层级中占比很高,但不影响组件1的层级),但组件1和其他兄弟组件层级相同(父元素组件1都被覆盖了子元素肯定被一起覆盖)。


结构问题:遮罩需要遮住视图不应该作为组件123的子组件,如果必须这样写,解决办法是使用Portal 将组件渲染到指定位置

ReactDOM.createPortal(需要渲染的元素,传送到的指定位置):渲染元素时将元素渲染到网页中的指定位置
1.在index.html中添加一个新的元素

<div id="root"></div>
<!--这个容器用来专门渲染遮罩层-->
<div id="backdrop"></div>

2.在组件中通过ReactDOM.createPortal()将元素渲染到新建的元素中

const backdropDOM = document.getElementById('backdrop');

// 在其他组件内部正常使用Backdrop组件,但是该组件渲染时会被传送到专门渲染遮罩层的容器中渲染,会脱离原来的结构
const Backdrop = () => {
  return ReactDOM.createPortal(
  <div>
  	{props.children}
  </div>,
      backdropDOM
  );
};

Fragment 组件

React中,JSX必须有且只有一个根元素,这导致在某些情况需要添加一个额外的父元素(并没有实际意义)

  • React提供了Fragment组件,Fragment可以让你聚合一个子元素列表,并且不在DOM中增加额外节点
  • <></>Fragment的语法糖,<></> 语法不能接受键值或属性,但Fragment可以传递 key 属性
import React from 'react';

const MyComponent = () => {
    return (
        <React.Fragment>
            <div>我是组件1</div>
            <div>我是组件2</div>
            <div>我是组件3</div>
        </React.Fragment>
        /*
        <>
            <div>我是组件1</div>
            <div>我是组件2</div>
            <div>我是组件3</div>
        </>
        */
    );
};

export default MyComponent;

Context 祖先组件向子孙组件传值

Context相当于一个公共的存储空间

创建content

// defaultValue存储的值
export const MyContext = React.createContext({
	name:xxx,
    age:xxx,
});

访问到Context中的数据

  • 方式1:通过Consumer标签来访问到Context中的数据(不常用)

    该组件内部必须使用函数,解析时会调用该函数,将创建的defaultValue作为该函数的参数传递。

    import React from 'react';
    import { MyContext } from '../store/test-context';
    
    const MyContext = () => {
    
        return (
            <MyContext.Consumer>
                {(ctx)=>{ // 上述案例中的defaultValue
                    return (
                        <ul>
                            <li>{ctx.name}</li>
                            <li>{ctx.age}</li>
                        </ul>
                    );
                }}
            </MyContext.Consumer>
    
        );
    };
    export default MyComponent;
    
  • 方式2:使用钩子函数useContext(context参数)获取到context,该钩子函数会返回Context中的数据

    import React, {useContext} from 'react';
    import { MyContext } from '../store/test-context';
    
    const MyComponent = () => {
        const ctx = useContext(MyContext);
        return (
            <ul>
                <li>{ctx.name}</li>
                <li>{ctx.age}</li>
            </ul>
        );
    };
    
    export default MyComponent;
    

​ 一般不会将数据直接放在Context,因为这样写是死数据并且与state响应式数据没什么关系,不会触发组件的重新渲染。所以React还提供了Provider组件,用于在数据所在的组件中指定Context值。

import React from "react";
import MyComponent from "./component/MyComponent";
import { MyContext } from "./store/test-context";

// 数据所在的组件
const App = () => {
	// 指定context的值
    return <MyContext.Provider value={{name:'猪八戒', age:28}}>
        /* Provider的子组件 */
        <MyComponent/>   
    </MyComponent.Provider>;
};

export default App;

Provider设置在外层组件中,通过value属性来指定Context的值。这个Context值在所有的Provider子组件中都可以访问。Context的搜索流程类似vueprovide inject

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UDP多人群聊

一&#xff0c;创建类 二&#xff0c;类 1&#xff0c;Liao类 import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.IOException; import java.lang.String;public class Liao extends JFrame{private static final int D…

图像处理中的角点检测Python-OpenCV 中的实现

马丁亚当斯 (Martin Adams)在Unsplash上拍摄的照片 一、说明 在图像处理的背景下&#xff0c;“特征”可以直观地理解为图像中易于识别并用于表示图像的独特或独特的部分。将特征视为图像中使其可区分的“地标”或“焦点”。为了使这一点更具关联性&#xff0c;请考虑一下您如…

JFrog Artifactory二进制文件管理工具部署使用

1.简介 JFrog Artifactory二进制文件管理工具&#xff0c;目前已经在使用的公司有很多&#xff0c;足见他的方便好用。 2.下载安装包 点击下载地址 这里我下载的是7.9.2版本 3. 安装 &#xff08;1&#xff09;在安装JFrog Artifactory之前需要安装好jdk&#xff08;需…

持续集成交付CICD:Sonarqube自动更新项目质量配置

目录 一、实验 1.Sonarqube手动自定义质量规则并指定项目 2.Sonarqube自动更新项目质量配置 一、实验 1.Sonarqube手动自定义质量规则并指定项目 &#xff08;1&#xff09;自定义质量规则 ①新配置 ②更多激活规则③根据需求激活相应规则④已新增配置 ⑤ 查看 &#x…

梯度下降(批量梯度下降、随机梯度下降、小批量梯度下降)

在上一篇中我们推导了损失函数 J ( θ ) 1 2 m ∑ i 1 m ( y i − h θ ( x i ) ) 2 J(\theta) \frac{1}{2m} \sum_{i1}^{m} (y^{i} - h_{\theta}(x^{i}))^2 J(θ)2m1​∑i1m​(yi−hθ​(xi))2的由来&#xff0c;结尾讲到最小化这个损失函数来找到最优的参数 θ \theta θ&…

【C++】简单工厂模式

2023年12月6日&#xff0c;周三下午 今天又学习了一次简单工厂模式 每多学习一次&#xff0c;都会加深对设计模式的理解 目录 什么是简单工厂模式简单工厂模式的优缺点举例说明 什么是简单工厂模式 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种创建型…

uni-app 微信小程序之加载行政区图

文章目录 1. 实现效果2. 实现步骤 1. 实现效果 2. 实现步骤 使用三方组件 ucharts echarts 高性能跨全端图表组件页面导入引入的三方组件 组件demo代码 <template><view class"qiun-columns"><view class"cu-bar bg-white margin-top-xs"…

管理和监控CentOS上的HTTP服务

CentOS作为一款稳定的开源服务器操作系统&#xff0c;为各种网络服务提供了优秀的支持。其中&#xff0c;HTTP服务是互联网上最常用的服务之一&#xff0c;它为人们提供了便捷的信息访问和交互方式。在CentOS上管理和监控HTTP服务是一项重要的任务&#xff0c;下面我们将介绍一…

华为配置风暴控制示例

组网需求 如下图所示&#xff0c;SwitchA作为二层网络到三层路由器的衔接点&#xff0c;需要防止二层网络转发的广播、未知组播或未知单播报文产生广播风 配置思路 用如下的思路配置风暴控制。 通过在GE0/0/1接口视图下配置风暴控制功能&#xff0c;实现防止二层网络转发的…

轻快小miniconda3在linux下的安装配置-centos9stream-Miniconda3 Linux 64-bit

miniconda与anaconda的区别&#xff1a; Miniconda 和 Anaconda 是用于管理环境和安装软件包的 Python 发行版。它们之间的主要区别在于以下几点&#xff1a; 1. 安装内容和大小&#xff1a; Anaconda&#xff1a; Anaconda 是一个完整的 Python 数据科学平台&#xff0c;包含…

10-tornado项目部署

1. python3的安装和配置 1.1 安装系统依赖包 sudo dnf install wget yum-utils make gcc openssl-devel bzip2-devel libffi-devel zlib-devel -y1.2 下载Python wget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tgz1.3 解压 tar xzf Python-3.9.5.tgz 1.4 安装…

Java实现TCP一对一通信,UDP协议实现群聊

实现服务端对话框&#xff1a; 其中可自行更改对话框大小样式等配置。 package com.ex.controller;import javax.servlet.http.HttpServletRequest; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; public class …

Centos服务器上根据端口号查询jar包,根据jar包查端口号

在开发springboot服务器时&#xff0c;经常会遇到其他人部署的java服务&#xff0c;需要自己维护&#xff0c;留下的信息又非常少。经常面临找不到jar包位置&#xff0c;或者不知道占用端口&#xff0c;不知道启动命令的问题。这里记录一下常用的centos服务器上的命令&#xff…

【桑基图】绘制桑基图

绘制桑基图 一、绘制桑基图&#xff08;1&#xff09;方法一&#xff1a;去在线网站直接绘制&#xff08;2&#xff09;方法二&#xff1a;写html之后在vscode上运行 二、遇到的问题&#xff08;1&#xff09;当导入一些excel的时候&#xff0c;无法绘制出桑基图 一、绘制桑基图…

ROS-ROS通信机制-参数服务器

文章目录 一、基础理论知识二、C实现三、Python实现 一、基础理论知识 参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点…

【LeetCode刷题】-- 79.单词搜索

79.单词搜索 方法&#xff1a;使用回溯 使用dfs函数表示判断以网格的(i.j)位置出发&#xff0c;能否搜索到word(k)&#xff0c;其中word(k)表示字符串word从第k个字符开始的后缀子串&#xff0c;如果能搜索到&#xff0c;返回true,反之返回false 如果board[i][j]≠word[k]&am…

李宏毅gpt个人记录

参考&#xff1a; 李宏毅机器学习--self-supervised&#xff1a;BERT、GPT、Auto-encoder-CSDN博客 用无标注资料的任务训练完模型以后&#xff0c;它本身没有什么用&#xff0c;GPT 1只能够把一句话补完&#xff0c;可以把 Self-Supervised Learning 的 Model做微微的调整&am…

分享一个Python网络爬虫数据采集利器

前言 你是否曾为获取重要数据而感到困扰&#xff1f;是否因为数据封锁而无法获取所需信息&#xff1f;是否因为数据格式混乱而头疼&#xff1f;现在&#xff0c;所有这些问题都可以迎刃而解。让我为大家介绍一款强大的数据收集平台——亮数据Bright Data。 作为世界领先的数据…

【Qt】QLineEdit显示输入十六进制,位数不足时按照规则填充显示及每两个字符以空格填充

问题 在实际开发中&#xff0c;有时候需要对输入进行限制&#xff0c;一是更加合理&#xff0c;二是防止出现误操作。 比如&#xff1a; 使用Qt进行应用程序开发时&#xff0c;对单行编辑框QLineEdit控件&#xff0c;设置只可输入十六进制。 限制输入的方式常用且经典的是使用…

限流算法,基于go的gRPC 实现的

目录 一、单机限流 1、令牌桶算法 3、固定窗口限流算法 4、滑动窗口 二、集群限流 1、分布式固定窗口 &#xff08;基于redis&#xff09; 2、分布式滑动窗口 一、单机限流 1、令牌桶算法 令牌桶算法是当流量进入系统前需要获取令牌&#xff0c;没有令牌那么就要进行限…