黑马React:基础拓展

黑马React: D10-基础拓展

Date: December 18, 2023


useReducer

基础使用

作用: 让 React 管理多个相对关联的状态数据

补充:和useState的作用类似,用来管理相对复杂的状态数据

**特点:**useReducer返回值为一个数组, 可以解构处数值state与修改数值的方法dispatch(修改数值的唯一方法)

案例:

  1. 定义一个reducer函数(根据不同的action返回不同的新状态)
  2. 在组件中调用useReducer,并传入reducer函数和状态的初始值
  3. 事件发生时,通过dispatch函数分派一个action对象(通知reducer要返回哪个新状态并渲染UI)
import { useReducer } from 'react'// 1. 定义reducer函数,根据不同的action返回不同的新状态
function reducer(state, action) {switch (action.type) {case 'INC':return state + 1case 'DEC':return state - 1default:return state}
}function App() {// 2. 使用useReducer分派actionconst [state, dispatch] = useReducer(reducer, 0)return (<>{/* 3. 调用dispatch函数传入action对象 触发reducer函数,分派action操作,使用新状态更新视图 */}<button onClick={() => dispatch({ type: 'DEC' })}>-</button>{state}<button onClick={() => dispatch({ type: 'INC' })}>+</button></>)
}export default App


更新流程

Untitled




分派action传参

**做法:**分派action时如果想要传递参数,需要在action对象中添加一个payload参数,放置状态参数

// 定义reducerimport { useReducer } from 'react'// 1. 根据不同的action返回不同的新状态
function reducer(state, action) {console.log('reducer执行了')switch (action.type) {case 'INC':return state + 1case 'DEC':return state - 1case 'UPDATE':return state + action.payloaddefault:return state}
}function App() {// 2. 使用useReducer分派actionconst [state, dispatch] = useReducer(reducer, 0)return (<>{/* 3. 调用dispatch函数传入action对象 触发reducer函数,分派action操作,使用新状态更新视图 */}<button onClick={() => dispatch({ type: 'DEC' })}>-</button>{state}<button onClick={() => dispatch({ type: 'INC' })}>+</button><button onClick={() => dispatch({ type: 'UPDATE', payload: 100 })}>update to 100</button></>)
}export default App



useMemo

**作用:**它在每次重新渲染的时候能够缓存计算的结果

语法:

useMemo(() => {// 根据 count1 返回计算的结果
}, [count1])

说明:使用 useMemo 做缓存之后可以保证只有 count1 依赖项发生变化时才会重新计算

**使用场景:**消耗非常大的计算可以使用 useMemo

使用技巧:

1-指这个空数组只会在组件渲染完毕之后执行一次,即只要这个固定的 [1, 2, 3] 稳定的数组引用

const list = useMemo(() => {return [1, 2, 3]
}, [])

看个场景

原本用意:基于count1的变化计算斐波那契数列之和,但是当我们修改count2状态的时候,斐波那契求和函数也会被执行,显然是一种浪费

Untitled

案例:

// useMemo
// 作用:在组件渲染时缓存计算的结果import { useState } from 'react'function factorialOf(n) {console.log('斐波那契函数执行了')return n <= 0 ? 1 : n * factorialOf(n - 1)
}function App() {const [count, setCount] = useState(0)// 计算斐波那契之和**const sum = factorialOf(count)**const [num, setNum] = useState(0)return (<>{sum}<button onClick={() => setCount(count + 1)}>+count:{count}</button><button onClick={() => setNum(num + 1)}>+num:{num}</button></>)
}export default App

Res:

Untitled



useMemo缓存计算结果

思路: 只有count发生变化时才重新进行计算

import { useMemo, useState } from 'react'function fib (n) {console.log('计算函数执行了')if (n < 3) return 1return fib(n - 2) + fib(n - 1)
}function App() {const [count, setCount] = useState(0)// 计算斐波那契之和// const sum = fib(count)// 通过useMemo缓存计算结果,只有count发生变化时才重新计算**const sum = useMemo(() => {return fib(count)}, [count])**const [num, setNum] = useState(0)return (<>{sum}<button onClick={() => setCount(count + 1)}>+count:{count}</button><button onClick={() => setNum(num + 1)}>+num:{num}</button></>)
}export default App


React.memo

**作用:**允许组件在props没有改变的情况下跳过重新渲染

组件默认的渲染机制

**默认机制:**顶层组件发生重新渲染,这个组件树的子级组件都会被重新渲染

Case1:

效果:点击按钮,数字不断增加,同时不断输出子组件内容。很明显,父组件的改变,子组件也会被跟着重新渲染改变。

import { useState } from "react";function Son() {console.log('我是子组件,我重新渲染了');return <div>this is son</div>
}function App() {const [count, setCount] = useState(0)return (<div className="App"><button onClick={() => setCount(count + 1)}>+{count}</button></div>)
}export default App

Res:

Untitled


Case2:

// memo
// 作用:允许组件在props没有改变的情况下跳过重新渲染import { useState } from 'react'function Son() {console.log('子组件被重新渲染了')return <div>this is son</div>
}function App() {const [, forceUpdate] = useState()console.log('父组件重新渲染了')return (<><Son /><button onClick={() => forceUpdate(Math.random())}>update</button></>)
}export default App

Res:

Untitled


Case3:

使用 useMemo 来缓存计算结果

import { useState ,memo, useMemo } from "react"// React.memo props比较机制// 1. 传递一个简单类型的prop  props变化时组件重新渲染
// 2. 传递一个引用类型的prop  比较的新值和旧值的引用地址是否相同,相同则不重新渲染,不同则重新渲染const MemoSon = memo(function Son({list}) {console.log('子组件重新渲染了')return <div>this is Son {list}</div>
})function App() {const [count, setCount] = useState(0)const list = useMemo(() => {return [1,2,3]}, [])return (<div className="App"><MemoSon count={list}></MemoSon><button onClick={() => setCount(count + 1)}>change count</button></div>)
}export default App;

Res:

Untitled



使用React.memo优化

**机制:**只有props发生变化时才重新渲染

下面的子组件通过 memo 进行包裹之后,返回一个新的组件MemoSon, 只有传给MemoSon的props参数发生变化时才会重新渲染

Case:

import { memo, useState } from "react";function Son() {console.log('我是子组件,我重新渲染了');return <div>this is son</div>
}const MemoSon = memo(function Son() {console.log('我是子组件,我重新渲染了');return <div>this is son</div>
})function App() {const [count, setCount] = useState(0)return (<div className="App"><button onClick={() => setCount(count + 1)}>+{count}</button><MemoSon/></div>)
}export default App

Res:

Untitled



props变化重新渲染

Case:

props变化子组件会重新渲染

import React, { useState } from 'react'const MemoSon = React.memo(function Son() {console.log('子组件被重新渲染了')return <div>this is span</div>
})function App() {console.log('父组件重新渲染了')const [count, setCount] = useState(0)return (<><MemoSon count={count} /><button onClick={() => setCount(count + 1)}>+{count}</button></>)
}export default App

Res:

Untitled



props的比较机制

对于props的比较,进行的是‘浅比较’,底层使用 Object.is 进行比较,针对于对象数据类型,只会对比俩次的引用是否相等,如果不相等就会重新渲染,React并不关心对象中的具体属性

举个例子:

// prop是简单类型
Object.is(3, 3) => true //没有变化// prop是引用类型(对象/数组)
Object([], []) => false // 有变化,React只关心引用是否变化

Case1:

传递一个简单数据类型

import { useState ,memo } from "react"// React.memo props比较机制// 1. 传递一个简单类型的prop  props变化时组件重新渲染
// 2. 传递一个引用类型的prop  比较的新值和旧值的引用地址是否相同,相同则不重新渲染,不同则重新渲染const MemoSon = memo(function Son({count}) {console.log('子组件重新渲染了')return <div>this is Son {count}</div>
})function App() {const [count, setCount] = useState(0)const num = 100return (<div className="App"><MemoSon count={num}></MemoSon><button onClick={() => setCount(count + 1)}>change count</button></div>)
}export default App;

Res:

无返回

Case2:

传递一个复杂数据类型list。每次当我们点击 button 按钮的时候,都会引发父组件的重新渲染,从而也会引发 const list= [1, 2, 3] 的重新执行,因为其引用地址也会改变

import { useState ,memo } from "react"// React.memo props比较机制// 1. 传递一个简单类型的prop  props变化时组件重新渲染
// 2. 传递一个引用类型的prop  比较的新值和旧值的引用地址是否相同,相同则不重新渲染,不同则重新渲染const MemoSon = memo(function Son({list}) {console.log('子组件重新渲染了')return <div>this is Son {list}</div>
})function App() {const [count, setCount] = useState(0)const list = [1, 2, 3]return (<div className="App"><MemoSon count={list}></MemoSon><button onClick={() => setCount(count + 1)}>change count</button></div>)
}export default App;

Res:

Untitled

说明:虽然俩次的list状态都是 [1,2,3] , 但是因为组件App俩次渲染生成了不同的对象引用list,所以传给MemoSon组件的props视为不同,子组件就会发生重新渲染



自定义比较函数

如果上一小节的例子,我们不想通过引用来比较,而是完全比较数组的成员是否完全一致,则可以通过自定义比较函数来实现

import React, { useState } from 'react'// 自定义比较函数
function arePropsEqual(oldProps, newProps) {console.log(oldProps, newProps)return (oldProps.list.length === newProps.list.length &&oldProps.list.every((oldItem, index) => {const newItem = newProps.list[index]console.log(newItem, oldItem)return oldItem === newItem}))
}const MemoSon = React.memo(function Son() {console.log('子组件被重新渲染了')return <div>this is span</div>
}, arePropsEqual)function App() {console.log('父组件重新渲染了')const [list, setList] = useState([1, 2, 3])return (<><MemoSon list={list} /><button onClick={() => setList([1, 2, 3])}>内容一样{JSON.stringify(list)}</button><button onClick={() => setList([4, 5, 6])}>内容不一样{JSON.stringify(list)}</button></>)
}export default App


useCallback

看个场景

上一小节我们说到,当给子组件传递一个引用类型prop的时候,即使我们使用了memo 函数依旧无法阻止子组件的渲染,其实传递prop的时候,往往传递一个回调函数更为常见,比如实现子传父,此时如果想要避免子组件渲染,可以使用 useCallback缓存回调函数

Case:

当我们给子组件传入函数时,由于函数也会引用数据类型,所以即使使用memo进行缓存控制,也会造成 父组件刷新 时,导致子组件同样刷新的问题

import { useState ,memo, useMemo, onChange } from "react"const Input = memo(function Input({ onChange }) {console.log(('子组件重新渲染了'))return <input type="text" onChange={(e) => onChange(e.target.value)}></input>
})function App() {// 传给子组件的函数const changeHandler = (value) => console.log(value);// 触发父组件重新渲染的函数const [count, setCount] = useState(0)return (<div className="App">{/* 把函数作为 prop 传递给子组件 */}<Input onChange={changeHandler}></Input><button onClick={() => setCount(count + 1)}>{count}</button></div>)
}export default App;

Res:

当我们不断点击按钮时,数字不断增加的同时,控制台也在不断输出子组件中的语句

Untitled



useCallback缓存函数

**作用:**在组件多次重新渲染的时候缓存函数

语法:

const changeHandler = useCallback((value) => console.log(value), [])

参数:1-需要缓存的函数 2-依赖项

  • 对2的补充说明

    []代表我们只需要将其缓存一次,后面的引用一直保持稳定。如果你想在依赖项变化的时候更新,那就传入一个依赖项即可。

理解:useCallback缓存之后的函数可以在组件渲染时保持引用稳定,也就是返回同一个引用

Case:

// useCallBackimport { memo, useCallback, useState } from 'react'const MemoSon = memo(function Son() {console.log('Son组件渲染了')return <div>this is son</div>
})function App() {const [, forceUpate] = useState()console.log('父组件重新渲染了')const onGetSonMessage = useCallback((message) => {console.log(message)}, [])return (<div><MemoSon onGetSonMessage={onGetSonMessage} /><button onClick={() => forceUpate(Math.random())}>update</button></div>)
}export default App

Res:

Untitled



forwardRef

**作用:**允许组件使用ref将一个DOM节点暴露给父组件

语法:

const Son = forwardRef((props, ref) => {return <input type="text" ref={ref}/>
})

参数:

1-props:指给子组件传递的参数 2-ref:通过ref来绑定子组件,从而在父组件上拿到子组件

Case1:

不使用 forwardRef

import { useRef } from "react"// 子组件
function Son() {return <input />
}// 父组件
function App() {const sonRef = useRef(null)const showRef = () => {console.log(sonRef);}return (<><Son ref={sonRef} /><button onClick={showRef}>focus</button></>)
}export default App

Res:

Untitled

Case2:

通过 ref 获取

import { forwardRef, useRef } from "react"// 子组件
// function Son() {
//   return <input />
// }const Son = forwardRef((props, ref) => {return <input type="text" ref={ref} />
})// 父组件
function App() {const sonRef = useRef(null)const showRef = () => {console.log(sonRef);sonRef.current.focus()}return (<><Son ref={sonRef} /><button onClick={showRef}>focus</button></>)
}export default App

Res:

Untitled




useImperativeHandle

**作用:**如果我们并不想暴露子组件中的DOM而是想暴露子组件内部的方法

语法:

const Input = forwardRef((props, ref) => {const inputRef = useRef(null)// 实现聚焦逻辑函数const focusHandler = () => {inputRef.current.focus()}// 暴露函数给父组件调用useImperativeHandle(ref, () => {return {focusHandler}})return <input type="text" ref={inputRef}/>
})

Case:

import { forwardRef, useImperativeHandle, useRef } from "react"// 子组件
const Son = forwardRef((props, ref) => {const inputRef = useRef(null)// 实现聚焦逻辑函数const focusHandler = () => {inputRef.current.focus()}// 暴露函数给父组件调用useImperativeHandle(ref, () => {return {focusHandler}})return <input type="text" ref={inputRef}/>
})// 父组件
function App() {const sonRef = useRef(null)const focusHandler = () => {console.log(sonRef.current);sonRef.current.focusHandler()}return (<><Son ref={sonRef} /><button onClick={focusHandler}>focus</button></>)
}export default App

Res:

Untitled




Class API

**概念:**顾名思义,Class API就是使用ES6支持的原生Class API来编写React组件

特点:

1-通过类属性 state 定义状态数据

2-通过 setState 方法来修改状态数据

3-通过 render 来写UI模版(JSX语法一致)

Case:

通过一个简单的 Counter 自增组件看一下组件的基础编写结构:

// class API
import { Component } from 'react'class Counter extends Component {// 状态变量state = {count: 0,}// 事件回调clickHandler = () => {// 修改状态变量 触发UI组件渲染this.setState({count: this.state.count + 1,})}// UI模版render() {return <button onClick={this.clickHandler}>+{this.state.count}</button>}
}function App() {return (<div><Counter /></div>)
}export default App

Res:

Untitled



组件生命周期

**概念:**组件从创建到销毁的各个阶段自动执行的函数就是生命周期函数

图示:

Untitled

  1. componentDidMount:组件挂载完毕自动执行 - 异步数据获取
  2. componentWillUnmount: 组件卸载时自动执行 - 清理副作用,比如定时器或者事件绑定

Case:

基础案例:卸载组件

 // Class API 生命周期import { Component, useState } from "react";class Son extends Component {// 生命周期函数// 挂载时:组件渲染完毕执行一次。用于:发送网络请求componentDidMount() {console.log('组件渲染完毕了,请求发送起来')}// 卸载时:组件卸载前执行一次。用于:清理副作用componentWillUnmount() {console.log('组件卸载了')}render() {return <div>SSSon</div>}
}function App() {const [show, setShow] = useState(true)return (<>{show && <Son />}<button onClick={() => setShow(false)}>unmount</button></>)
}export default App

Res:

Untitled

Case2:

问题:以下Case的son组件在卸载后,其中的 Interval 定时器仍然在继续运行,造成了内存泄漏

// Class API 生命周期import { Component, useState } from "react";class Son extends Component {// 生命周期函数// 挂载时:组件渲染完毕执行一次。用于:发送网络请求componentDidMount() {console.log('组件渲染完毕了,请求发送起来')// 开启定时器this.timer = setInterval(() => {console.log('定时器执行了')}, 1000)}// 卸载时:组件卸载前执行一次。用于:清理副作用componentWillUnmount() {console.log('组件卸载了')}render() {return <div>SSSon</div>}
}function App() {const [show, setShow] = useState(true)return (<>{show && <Son />}<button onClick={() => setShow(false)}>unmount</button></>)
}export default App

Res:

Untitled

修复后:

// Class API 生命周期import { Component, useState } from "react";class Son extends Component {// 生命周期函数// 挂载时:组件渲染完毕执行一次。用于:发送网络请求componentDidMount() {console.log('组件渲染完毕了,请求发送起来')// 开启定时器this.timer = setInterval(() => {console.log('定时器执行了')}, 1000)}// 卸载时:组件卸载前执行一次。用于:清理副作用componentWillUnmount() {console.log('组件卸载了')// 清除定时器**clearInterval(this.timer)**}render() {return <div>SSSon</div>}
}function App() {const [show, setShow] = useState(true)return (<>{show && <Son />}<button onClick={() => setShow(false)}>unmount</button></>)
}export default App

Res:

Untitled


组件通信

**概念:**类组件和Hooks编写的组件在组件通信的思想上完全一致

分类:

  1. 父传子:通过prop绑定数据
  2. 子传父:通过prop绑定父组件中的函数,子组件调用
  3. 兄弟通信:状态提升,通过父组件做桥接

使用总结:

1-思想保持一致,不管API怎么改变,父子通信的思想是一致的

2-类组件依赖于this

父传子

Case:

// class API
import { Component } from 'react'
// 1. 父传子 直接通过props子组件标签身上绑定父组件中的数据即可class Son extends Component {render() {// 使用this.props.msgreturn <div>我是子组件 {this.props.msg}</div>}
}class Parent extends Component {state = {msg: 'this is parent msg'}render() {return (<div><h1>我是父组件</h1><Son msg={this.state.msg}/></div>)}
}function App() {return (<><Parent /></>)
}export default App

Res:

Untitled


子传父

Case:

// class API
import { Component } from 'react'class Son extends Component {render() {const { msg, onGetSonMsg } = this.propsreturn (<><div>this is Son, {msg}</div><button onClick={() => onGetSonMsg('this is son msg')}>changeMsg</button></>)}
}class App extends Component {// 状态变量state = {msg: 'this is initail app msg',}onGetSonMsg = (msg) => {this.setState({ msg })}// UI模版render() {return (<><Son msg={this.state.msg} onGetSonMsg={this.onGetSonMsg} /></>)}
}export default App

Res:

Untitled

参考:

Component – React 中文文档

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

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

相关文章

C++共享和保护——(4)保护共享数据

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 一滴汗珠万粒粮&#xff0c;万粒汗珠谷…

【04】GeoScene导出海图或者电子航道图000数据成果

1创建一个带有覆盖面和定义的产品 如果你没有已存在的S-57数据&#xff0c;你可以通过捕捉新的产品覆盖范围&#xff08;多边形产品范围&#xff09;及其所需的产品定义信息&#xff08;产品元数据&#xff09;来为新产品创建基础。 注&#xff1a; 如果你已经有一个S-57数据…

【NI-RIO入门】使用LabVIEW进行数据采集测量

于ni kb摘录 选择合适的编程模式 CompactRIO系统具有至少两个用户可选模式。某些CompactRIO型号具有附加的用户可选模式&#xff0c;可以在实时NI-DAQmx中进行编程。请参考本文以判断您的CompactRIO是否能够使用实时NI-DAQmx。将目标添加到项目后&#xff0c;将提示您选择要使…

wvp-GB28181-pro 2.0+ZLMediaKit 使用Dockerfile制作镜像以及部署【CentOS7】

说明 部署gb28181和zlm主要需要构建两个镜像&#xff0c;第一个为基础镜像&#xff0c;以centos7为基础构建新的基础镜像base.Dockerfile,第二个镜像为服务部署镜像server.Dockerfile&#xff0c;以第一个镜像base.Dockerfile构建出的镜像为基础镜像进行构建 整个基础镜像的构…

Python项目——表白照片墙

1、介绍 利用女神的照片&#xff0c;组成女神的名字&#xff0c;向女神表白。如下图&#xff1a; 原理&#xff1a;获取每个像素点的颜色&#xff0c;白色不贴图&#xff0c;黑色贴图。 2、工具 语言&#xff1a;python3.11编译器&#xff1a;PyCharm包&#xff1a;pygame p…

2024年【陕西省安全员C证】考试及陕西省安全员C证模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 陕西省安全员C证考试是安全生产模拟考试一点通总题库中生成的一套陕西省安全员C证模拟试题&#xff0c;安全生产模拟考试一点通上陕西省安全员C证作业手机同步练习。2024年【陕西省安全员C证】考试及陕西省安全员C证模…

竞赛保研 python+opencv+深度学习实现二维码识别

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; pythonopencv深度学习实现二维码识别 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 该项目较为新颖&…

JWT令牌的作用和生成

JWT令牌&#xff08;JSON Web Token&#xff09;是一种用于身份验证和授权的安全令牌。它由三部分组成&#xff1a;头部、载荷和签名。 JWT令牌的作用如下&#xff1a; 身份验证&#xff1a;JWT令牌可以验证用户身份。当用户登录后&#xff0c;服务器会生成一个JWT令牌并返回…

hping3

Hping3 Hping3的介绍&#xff1a; 是一款网络的测试工具&#xff0c;一般用于网络安全员用来进行防火墙的测试等抗压测试。 Hping3的帮助面板: -h –help显示帮助 -v –version显示版本信息 -c –count 限制发包数 -i –interval nterval 指定发包间隔为多少毫秒&#…

一封来自北京软协的感谢信

日前&#xff0c;北京软件和信息服务业协会&#xff08;以下简称北软协&#xff09;向酷雷曼&#xff08;北京同创蓝天云科技有限公司&#xff09;发来感谢信&#xff0c;以表彰和感谢同创蓝天对北软协及行业的全方位支持和卓越贡献。 作为北软协理事会会员单位&#xff0c;酷雷…

js 高阶(含vue.js)

1、主动触发函数 this.$options.watch.watchOrdersFormPrice.apply(this);//主动触发watchOrdersFormPrice watch:{watchOrdersFormPrice: function(){if( !this.ordersForm.alone_sold_price && this.ordersForm.ginfo.goods_id ){var price_info this.ordersForm.…

汽车销售技巧培训应该学习哪些内容

汽车销售技巧培训应该学习哪些内容 随着汽车市场的竞争日益激烈&#xff0c;汽车销售技巧培训对于提高销售人员的销售能力和服务水平至关重要。本文将介绍汽车销售技巧培训应该学习哪些内容&#xff0c;并结合案例进行分析。 一、产品知识 作为销售人员&#xff0c;了解所销售…

Java 图片文件上传下载处理

Java 图片文件上传下载处理 下载 做这玩意给我恶心坏了 下载 直接访问上传的路径就可以下载图片了。但是我们往往会包一层接口&#xff0c;以流的方式读取 url 的内容然后返回给前端&#xff0c;这么做的优点是&#xff1a; 内网域名转外网域名&#xff0c;做业务校验并且让用…

后端相关随机题目记录(1)

目录 后端相关随机题目记录&#xff08;1&#xff09; 后端相关随机题目记录&#xff08;1&#xff09;Bean的类型以及作用域Bean的生命周期Mysql的底层数据结构RedisHttp和Https区别AOP在项目的应用 自定义注解&#xff1f;请求在spring中的一个流程Nacos与zk的区别SpringMV…

Unity中URP下的菲涅尔效果实现(个性化修改)

文章目录 前言一、我们修正一下上篇文章中&#xff0c;可能遗留的Bug1、N向量 变为 单位向量2、使颜色范围在合理区间 二、实现菲涅尔效果强弱可自定义调节三、修改菲涅尔效果颜色1、在属性面板定义颜色属性2、在常量缓冲区申明该参数3、在片元着色器中&#xff0c;用颜色和菲涅…

Python---进程

1. 进程的介绍 在Python程序中&#xff0c;想要实现多任务可以使用进程来完成&#xff0c;进程是实现多任务的一种方式。 2. 进程的概念 一个正在运行的程序或者软件就是一个进程&#xff0c;它是操作系统进行资源分配的基本单位&#xff0c;也就是说每启动一个进程&#xf…

QT for Android安卓编译环境搭建+首次编译3个大坑

1、安装 编译环境能否搭建成功&#xff0c;主要是看各个依赖软件的版本是否匹配。依赖的软件有3个&#xff1a;JDK、安卓SDK、安卓NDK。 我的qt版本是5.14.1&#xff0c;我亲测以下版本可以成功让编译安卓&#xff1a; QT5.14 JDK1.8.0 安卓SDK26.1 安卓NDK20.1 在QT-&g…

LeetCode 142. 环形链表 II

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整…

【网络安全】-Linux操作系统—操作系统发展历史与Linux

文章目录 操作系统发展历史初期的操作系统分时操作系统个人计算机操作系统 Linux的诞生UNIX与GNU项目Linux内核的创建 Linux的特点开放源代码多样性社区支持 Linux的应用服务器和超级计算机嵌入式系统桌面系统 总结 操作系统发展历史 操作系统&#xff08;Operating System&am…

Linux之FTP 服务器

一、FTP服务器匿名账户服务器配置 1、测试是否已安装vsftp服务器&#xff1a; 2、启动vsftp服务器&#xff1a; 3、修改vsftp主配置文件&#xff0c;允许匿名登录 4、重新启动vsftpd服务,禁用防火墙 5、打开FTP服务的数据文件存放目录/var/ftp&#xff0c;复制若干文件到该目…