免费网站建设加盟,莱芜手机网站设计公司,网页设计概览图,seo白帽优化文章目录 react学习笔记01入门概述React 基础案例HelloWorld三个API介绍 JSXJSX 解构数组 创建react项目(手动)创建React项目(自动) | create-react-app事件处理React中的CSS样式内联样式 | 内联样式中使用state (不建议使用)外部样式表 | CSS Module React组件函数式组件和类组… 文章目录 react学习笔记01入门概述React 基础案例HelloWorld三个API介绍 JSXJSX 解构数组 创建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 祖先组件向子孙组件传值 Effect 副作用setState()在函数组件中的执行流程React.StrictMode react学习笔记01
学习视频 react18 李立超
学习中get到的新用法 Date类的toLocalString方法可以更为灵活的处理Date类。 标签属性中闭包的使用 举例仅在删除状态时使用id不需要单独传递id属性。 const logItemDate logsData.map(item LogItem onDelLog {() delLog(item.id)})移动端适配 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入门
概述
AJAXDOM可以实现网页的局部刷新但是新数据不能直接在网页中显示需要通过DOM将数据转换为网页中的节点。
react帮助我们根据不同的数据来快速构建用户项目,同时在构建过程中确保其流畅度。
react特点
1.使用虚拟DOM而不是真正的DOM
2.声明式编码(声明式:结果为导向,不关心结果 命令式:一行代码一个命令)
3.支持服务器端渲染
React 基础案例HelloWorld
入门案例采用外部引入脚本使用(正常开发使用包管理器)
react.development.js react 是react核心库只要使用react就必须要引入。下载地址react-dom.development.js react-dom 是react的dom包使用react开发web应用时必须引入。下载地址babel.min.js 浏览器不能识别JSX利用该babel将JSX转换为JS代码。下载地址
1.引入脚本
script src../script/react.development.js/script
script src../script/react-dom.development.js/script2.创建一个React元素
React.createElement(组件名/元素名,元素中的属性,元素的子元素/内容)
const reactDiv React.createElement(div,{},我是react创建的div); 3.获取根元素对应的React元素 ReactDOM.createRoot(Dom元素);
// html
div idroot/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都会被替换后续的调用则会使用React的DOM差分算法(diff)进行更新
JSX
上述方法中React.createElement(button, {}, 我是按钮)还是命令式编码方法告诉react用createElement去创建一个button按钮该按钮没有属性内容为我是按钮。
声明式编程结果导向告诉结果不关系过程怎么样。
const button button我是按钮/button; // 告诉react我需要一个button按钮元素不关心react如何创建在React中可以通过JSXJavaScript Syntax Extension来创建React元素JSX 让我们以类似于HTML 的形式去使用 JS。JSX是React中声明式编程的体现方式。
JSX需要被翻译为JS代码才能被React执行。 要在React中使用JSX必须引入babel来完成“翻译”工作。 JSX就是React.createElement()的语法糖最终都会转换为以调用React.createElement()创建元素的代码。 JSX在执行之前都会被babel转换为JS代码 !-- 引入babel --
script srcscript/babel.min.js/script
!--设置js代码被babel处理--
script typetext/babelconst div div我是一个divbutton我是按钮/button/div;const root ReactDOM.createRoot(document.getElementById(root));root.render(div);
/scriptJSX不是字符串不需要加引号
const div div我是一个div/div // 正确写法 JSX中html标签应该小写开头React组件应该大写开头
div // 小写html标签
Div // 大写组件JSX有且只有一个根标签 JSX的标签必须正常结束(自结束标签必须写/)
const input input typetext / 在JSX中使用{}嵌入表达式(有值的语句就是表达式)
const name ranran
const div div{name}/div // 才会显示ranran,没有括号会把name识别为字符串如果表达式值为空值、布尔值、undefined将不会显示 在JSX属性可以直接在标签中设置 事件绑定需要是一个函数而不能直接是函数调用(绑定时就会被触发不会延迟触发)className代替classstyle必须使用对象设置属性名必须用驼峰命名法
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 divhello {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通过虚拟DOM将React元素和原生DOM元素进行映射
当我们调用root.render时。页面就会发生重新渲染 React通过diff算法将新的虚拟DOM和旧的比较找到发生变化的元素并且只对变化的元素进行修改。
数组中(当前数组)每一个元素都需要设置一个唯一key值 重新渲染页面时React 有key值会比较key值相同的元素没key值会按照顺序进行比较。
开发中一般会采用数据的 id 作为 key尽量不使用元素的 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打包才能在浏览器中正常执行。 创建React
根目录- public(可以web直接访问的文件,不用打包就可以浏览器访问的静态资源)- index.html 入口文件必须有首页模板打包时以此为模板生成最终的index/html | 添加标签 div idroot/div- src(源码JS源代码)- index.js(必须webpack打包文件的入口该文件会被自动引入public/index.html中)pnpm init 初始化项目生成package.json文件(大部分时候这一步可以省略)pnpm install react react-dom react-scripts 安装项目依赖编写代码src/index.js
// 引入ReactDOM
import ReactDOM from react-dom/client;// 创建一个JSX
const APP divh1这是一个react项目/h1/div// 获取一个根元素
const root ReactDOM.createRoot(document.getElementById(root));
// 将APP渲染进根容器
root.render(APP);运行项目
pnpm react-scripts build 打包项目一般开发完成之后需要上线时使用该命令进行打包。 初次需要输入y确认。打包时需要默认配置会询问是否添加默认配置。 正常情况右键打开会报错。因为打包好的文件需要部署在服务器上运行而不是直接使用浏览器打开。每次打包后路径都是这样需要手动修改。 pnpm react-scripts start 开发中使用的命令 通过webpack启动内部的测试服务器可以实时对更新代码进行编译。这个命令太长可以在package.json的 scripts 选项中配置命令下次可以使用命令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.html和src/index.js必须保留外其他的东西都是可以删除的。
/*reate-react-app 创建index.js其中React.StrictMode使用严格模式渲染React元素 - 可以不使用
*/
const root ReactDOM.createRoot(document.getElementById(root));
root.render(React.StrictModeaaa/React.StrictMode
);
事件处理
react 元素的事件处理和 DOM 元素的很相似但是有一点语法上的不同 React 事件的命名采用小驼峰式camelCase而不是纯小写。 使用 JSX 语法时需要传入一个函数作为事件处理函数。事件绑定需要是一个函数而不能直接是函数调用(绑定时就会被触发不会延迟触发等于将函数的返回值给了该事件) // 传统 HTML
button onclickactivateLasers()Activate Lasers
/button
// React
button onClick{activateLasers} Activate Lasers
/buttonReact事件通过会传递事件对象event但其不同于原生的事件对象是React包装后的事件对象该对象已经处理了跨浏览器的兼容性问题。 React中事件回调函数不能通过返回false阻止默认行为必须显式地使用event事件对象的preventDefault方法 // 传统 HTMLform οnsubmitconsole.log(You clicked submit.); return falsebutton typesubmitSubmit/button
/form// React
function Form() {function handleSubmit(e) {e.preventDefault(); console.log(You clicked submit.);}return (form onSubmit{handleSubmit}button typesubmitSubmit/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}我是Divbutton onClick{toggleBorderHandler}切换边框/button/div);
};export default StyleDemo;外部样式表 | CSS Module
外部样式是指将样式编写到外部的css文件中直接通过import引用。
直接import引入的样式都是全局样式其他组件也看得见这个样式。如果不同的样式表中出现了相同的类名会出现相互覆盖情况。
import ./index.cssCSS Module 使用CSS Module后网页中元素的类名会自动计算生成并确保唯一。 如果引用同一个模块计算出来的类名是相同的。 CSS Module在React中已经默认支持(前提是使用了react-script)
文件样式的文件名为xxx.module.css在组件中引入样式的格式为import xxx from ./xxx.module.css设置类名时通过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 reactclass App extends Component{state {count:0,age:{} } divRef React.createRef();// 事件回调函数需要定义为类的方法,建议使用箭头函数这样this指向的是react实例。否则函数里的this会执行设置事件的dom元素clickHandler (){// 写法1:this.setState({count:this.state.count1})// 写法2this.setState(prevCount {return {count:prevCount1;}})}retnder(){return divh1 ref{ divRef }this.propsh1h1 onClick{this.clickHandler}this.state.counth1 /div}
}生成一组标签/组件
在react中对于根据数组数据产生一组标签或者一组组件没有类似vue的v-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 bgColorred 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概述
state与props类似都是一种存储属性的方式。
state只属于当前组件(组件的私有属性)其他组件无法使用。state的值是对象当其内容发生变化相关组件会一起刷新
useState(stateInitValue)
通过钩子函数useState(stateInitValue)创建stateReact中钩子函数只能用于函数组件或自定义钩子。
参数是整个state变量的初始值函数返回一个数组[stateVariable,setStateFunction]第一个元素是state变量的初始值(只用于显示)第二个元素是修改该变量的函数(函数的参数为新值)。调用修改函数修改state变量的值(state值发生变化)会触发组件的重新渲染直接修改state变量不会触发组件的重新渲染。
import { useState } from Reactconst [stateVariable,setStateFunction] useState(1);注意点
当state值是一个对象时setState()修改时使用新的对象去替换已有对象。
const [user, setUser] useState({name:ranran,age:18})
user.name xxx;
serUser(user); // user是对象对象的地址没有发生变化所以不会引起组件重新渲染/*
解决方案:将其拷贝给另一个新对象修改新对象的属性
*/
setUser({...user,name:xxx}) // 后面的name会覆盖前面的name通过setState()去修改一个state时并不表示修改当前的state修改的是组件下一次渲染的state setState()会触发组件的异步渲染(并不是马上调用就渲染放入事件循环队列中等待执行)所以当调用setState()需要使用state值时可能出现计算错误。 因为setState()修改的是下一次渲染的state如果下一次渲染还没进行前又调用了setState()此时state还是旧值所以就会出现计算错误。 解决办法 : 通过传递回调函数的形式修改state 回调函数的返回值会成为新的state值回调函数执行时React会将最新的state值作为参数传递。 setCount(state state1); // 传递参数React会保证参数的state是最新值如果setState()中需要用到旧值参数都采用函数的形式。
Ref 获取DOM对象
Ref是reference的简写用来获取真实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输入数据都是现用现取的。
受控组件使 React 的 state 成为唯一数据源由state控制表单。
数据的双向绑定
将表单的value绑定为state数据表单的onChange事件触发时通过事件对象event获取到新值然后使用setState修改state的值为新值。
import { useState } from react;
import ./index.css;const Demo () {// 如果有多个表单可以将表单数据设置为一个对象const [inputValue, setInputValue] useState();return (inputtypetextclassNameinputDemovalue{inputValue}onChange{e {setInputValue(e.target.value);}}//);
};export default Demo;子组件给父组件传值 props传递函数 子组件调用函数
在父组件中使用props给子组件传递一个自定义事件在子组件中将需要传递的数据作为函数参数调用函数
// 父组件
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 idroot/div
!--这个容器用来专门渲染遮罩层--
div idbackdrop/div2.在组件中通过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.Fragmentdiv我是组件1/divdiv我是组件2/divdiv我是组件3/div/React.Fragment/*div我是组件1/divdiv我是组件2/divdiv我是组件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){ // 上述案例中的defaultValuereturn (ulli{ctx.name}/lili{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 (ulli{ctx.name}/lili{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的搜索流程类似vue的provide 和 inject。
Effect 副作用
组件每次重新渲染组件的函数体就会执行。
有一部分逻辑如果直接写在函数体中会影响到组件的渲染这部分会产生“副作用”的代码是不能直接写在函数体中。 例如如果直接将修改state的逻辑编写到了组件之中每次函数体执行设置基础值state变量又引起组件的更新就会导致组件不断的循环渲染直至调用次数过多内存溢出。 setState()在函数组件中的执行流程
setState()会调用dispatchSetDate()方法dispatchSetDate()方法的主要逻辑 判断组件当前处于什么阶段(渲染阶段 |非渲染阶段 ) 处于渲染阶段不会检查state值是否相同在此时直接将setState设置的值放入渲染队列等待渲染 处于非渲染阶段检查setState设置的值与之前的值是否相同。如果值不同对组件进行重新渲染如果值相同则不对组件进行重新渲染。
处于渲染阶段案例
const App () {const [count,setCount] uesState(0);// 会触发Too many re-renders报错 // 调用的时候处于渲染阶段因为div没有渲染到页面上所以会引发重新渲染再次调用组件函数。也就是说无限循环不会退出渲染阶段。setCount(0); return (div{count}/div)
}处于非渲染阶段案例
第一次点击按钮count 0 - 1组件重新渲染。
第二次点击按钮count 1 - 1组件重新渲染。
第三次点击按钮count 1 - 1组件没有重新渲染。
这是因为当值相同时React在某些情况下(通常发生在值第一次相同时)会继续执行当前组件的渲染(这里指的时组件函数执行并更新页面)这次渲染不会产生实际效果(这里应该仅重新执行组件函数并不更新页面不触发刷新没有什么用)并且不会触发子组件的渲染。
const App () {const [count,setCount] uesState(0);const clickHandler (){setCount(1); }return (div onClick{ clickHandler }{count}/div)
}React.StrictMode
脚手架自动生成的index.jx中使用了该组件该组件表示react自身开启严格模式开启后react会自动去检查组件中是否有副作用的代码(并不是很智能)。
root.render(React.StrictModeApp//React.StrictMode
)React的严格模式在开发模式下会主动重复调用一些函数以使副作用出现。这些函数会被调用两次如果安装了React Developer Tool调试作用的第二次调用会显示为黑色。
类组件的 constructor, render, 和 shouldComponentUpdate 方法类组件的静态方法 getDerivedStateFromProps函数组件的函数体参数为函数的setState参数为函数的useState, useMemo, useReducer