如何撰写唐山网站制作案例设计说明?

摘要:唐山网站制作案例,设计说明怎么写200字,网站title字数,网站备案号的链接React(八)一、类组件的优劣势1.类组件的优势2.类组件的劣势(1&
唐山网站制作案例,设计说明怎么写200字,网站title字数,网站备案号的链接React#xff08;八#xff09;一、类组件的优劣势1.类组件的优势2.类组件的劣势#xff08;1#xff09;复杂组件会难以理解#xff08;2#xff09;复杂的class#xff08;3#xff09;组件复用状态很难二、Hook初体验useState1.使用Hook的计数器案例2.详解useState八一、类组件的优劣势1.类组件的优势2.类组件的劣势1复杂组件会难以理解2复杂的class3组件复用状态很难二、Hook初体验useState1.使用Hook的计数器案例2.详解useState1猜测它的原理2参数和返回值是什么3.使用Hook的一些规则三、useEffect使用详解1.基本使用方式和细节2.清除Effect如事件监听、订阅3.可以使用多个useEffect4.决定useEffect的执行次数一、类组件的优劣势 1.类组件的优势 之前我们一直用类组件写demo类组件相对于函数组件有什么优势 类组件可以保存组件自己的状态但是在函数组件中修改数据页面不会重新渲染而且就算重新渲染重新执行函数又重新赋值等于没改。 import React, { PureComponent } from react// 函数组件 function HelloHooks() {// 就算函数重新执行, 又会重新赋值, 无意义let message Hello Hooksreturn(divh2{message}/h2/div) }export class App extends PureComponent {render() {return (divHellWorld/HelloHooks//div)} }export default App类组件有自己的生命周期钩子比如我们在componentDidMount中发送网络请求并且该生命周期函数只会执行一次。但是函数组件在哪里发请求呢如果在函数中发请求那么每次重新渲染又重新调用函数又重新发请求这样反复发请求很沙雕。 class组件可以在状态改变时, 只重新执行render函数以及我们希望重新调用的生命周期函数如componentDidUpdate函数式组件在重新渲染时整个函数都会被执行似乎没有什么地方可以只让它们内部的某段代码只执行一次。 所以在Hook之前通常都用类组件写项目。 2.类组件的劣势 1复杂组件会难以理解 随着业务的增多我们的class组件会变得越来越复杂; 比如componentDidMount中可能就会包含大量的逻辑代码包括网络请求、一些事件的监听(还需要在 componentWillUnmount中移除); 而对于这样的class实际上非常难以拆分因为它们的逻辑往往混在一起强行拆分反而会造成过度设计增加代码的复杂度; 2复杂的class 最显著的问题就是this的指向问题如果this不处理好可能会出现一些错误。 3组件复用状态很难 比如我们之前使用redux中的数据需要用connect这样的高阶组件或者如果想实现什么功能还需要自己封装高阶组件给类组件注入一些东西这还是非常费劲的。 二、Hook初体验useState 如果是一个旧的项目你并不需要直接将所有的代码重构为Hooks因为它完全向下兼容你可以渐进式的来使用它; Hook只能在函数组件中使用不能在类组件或者函数组件之外的地方使用; 1.使用Hook的计数器案例 之前用类组件的写法我们都很熟知了 import React, { PureComponent } from reactexport class Counter1 extends PureComponent {constructor() {super()this.state {counter: 10}}changeNumber(num) {this.setState({counter: this.state.counter num})}render() {const { counter } this.statereturn (divh2当前计数: {counter}/h2button onClick{() this.changeNumber(-1)}-1/buttonbutton onClick{() this.changeNumber(1)}1/button/div)} }export default Counter1我们再看看用函数式组件这个东西怎么写 import React, { memo, useState } from react;const Counter memo(() {let [counter, setCounter] useState(99);return (divh2Counter{counter}/h2button onClick{() setCounter(counter1)}点击让Counter1/button/div) })export default Counter真的是非常的简洁而且没有this的指向问题。 2.详解useState 1猜测它的原理 它与class组件里面的 this.state 提供的功能完全相同就是用来保存状态数据的。 上面的代码点击按钮会发生两件事情 1、调用setCounter修改counter 2、组件重新渲染函数重新执行根据新值返回DOM结构 一般来说在函数退出后变量就会”消失”而 state 中的变量会被 React 保留。我盲猜这里用到了闭包setCounter函数内部保存了state中的原始变量等到setCounter函数被调用后原始变量才会被销毁数据更改后再重新执行函数组件并把新值传过去此时数据就有了最新的值。当然只是盲猜 2参数和返回值是什么 useState只有一个参数 接收一个初始化状态的值(设置初始值)在第一次组件被调用时使用来作为初始化值如果不设置则默认为undefined。 useState的返回值: 返回一个数组数组包含两个元素 元素1当前状态的值第一次调用为初始值元素2修改状态的函数 一般我们会对数组进行解构名字当然是自己取 let [counter, setCounter] useState(99);3.使用Hook的一些规则 通过上面的讲解可以感受到hook顾名思义就是把要用的东西钩过来用一下子。 使用Hook的规则 1、只能在函数组件的顶层调用 Hook。不能在循环语句、条件判断语句或者子函数中调用。 2、只能在 React 的函数组件和自定义hook中调用 Hook。不能在其他 JavaScript 函数中调用。 当然我们可以定义更多类型的数据。 也可以把修改的操作单独封装一个函数。 import React, { memo, useState } from react;const Counter memo(() {let [counter, setCounter] useState(99);let [newsList, setNewsList] useState([体育,娱乐]);let [userInfo, setUserInfo] useState({name:zzy,age:18});function changeNum() {setCounter(counter - 1);}return (divh2Counter{counter}/h2button onClick{() setCounter(counter1)}点击让Counter1/buttonbutton onClick{changeNum}点击让Counter-1/buttonh3{newsList}/h3h3{userInfo.name}-{userInfo.age}/h3/div) })export default Counter三、useEffect使用详解 在类组件中是可以有生命周期函数的, 那么如何在函数组件中定义类似于生命周期这些函数呢? 答案就是useEffect钩子 顾名思义其实我们平时的网络请求、手动更新DOM、一些事件的监听、订阅redux数据变化等操作都是除了更新DOM之外需要做的操作也就是一些副作用effect 1.基本使用方式和细节 比如一个这样的案例修改counter时实现页面标题和counter同步变化 类组件实现 import React, { PureComponent } from reactexport class App extends PureComponent {constructor() {super()this.state {counter: 100}}// 进入页面时, 标题显示countercomponentDidMount() {document.title this.state.counter}// 数据发生变化时, 让标题一起变化componentDidUpdate() {document.title this.state.counter}render() {const { counter } this.statereturn (divh2{counter}/h2button onClick{() this.setState({counter: counter1})}1/button/div)} }export default App不难看出类组件想要实现这个效果需要写两个生命周期钩子componentDidMount只有第一次挂载完成会执行componentDidUpdate在每次更新结束后会执行。 那么函数组件怎么实现这个效果呢答案是使用useEffect import React, { memo, useEffect, useState } from reactconst App memo(() {const [counter, setCounter] useState(200)// useEffect传入一个回调函数, 在页面渲染完成后自动执行useEffect(() {// 一般在该回调函数在编写副作用的代码(网络请求, 操作DOM, 事件监听)document.title counter})return (divh2{counter}/h2button onClick{() setCounter(counter1)}1/button/div) })export default AppuseEffect传入一个回调函数, 这个回调函数在每次页面渲染完成后自动执行。也就是说每次在函数式组件执行的顺序是 执行函数组件 定义初始状态 渲染DOM 执行useEffect中的回调 修改数据 重新执行函数组件 更新状态 渲染最新DOM 执行useEffect中的回调 不难看出其实useEffect中的回调相当于完成了componentDidMount和componentDidUpdate做的事情。 2.清除Effect如事件监听、订阅 在类组件的编写过程中某些副作用的代码我们需要在componentWillUnmount中进行清除比如事件总线或redux的数据订阅那这在函数式组件中怎么做呢 useEffect传入的回调函数A本身可以有一个返回值这个返回值是另外一个回调函数B useEffect(() {console.log(订阅了redux,绑定了某个事件A)return () {console.log(取消订阅redux,解绑某个事件A)} })返回的这个回调函数执行的时机有两个组件即将更新数据、组件即将卸载。 什么意思呢如果我们在useEffect回调中绑定了某个事件那么每次更新数据每次都要渲染DOM每次渲染DOM就会引起每次useEffect回调重新执行这样的话相当于只要更新数据就反复绑定事件嘚儿嘚儿嘚儿绑定一堆事件这显然有点奥里给啊。 所以说我们可以协商这个返回的回调函数每次更新数据前先执行回调解绑事件再更新再绑定事件也就是同样的事件每次只绑定一个就够啦。 3.可以使用多个useEffect 使用Hook的其中一个目的就是解决class中生命周期经常将很多的逻辑放在一起的问题: 比如网络请求、事件监听、手动修改DOM这些往往都会放在componentDidMount中; 一个函数组件中可以使用多个Effect Hook我们可以将逻辑分离到不同的useEffect中: import React, { memo } from react; import { useState, useEffect } from react;const Counter memo(() {let [counter, setCounter] useState(99);useEffect(() {//当前回调会在页面渲染完成后重新执行每次都重新执行document.title counter;})useEffect(() {console.log(订阅了redux,绑定了某个事件A)return () {console.log(取消订阅redux,解绑某个事件A)}})useEffect(() {console.log(发送网络请求的逻辑)})return (divh2Counter{counter}/h2button onClick{() setCounter(counter 1)}点击让Counter1/button/div) }) export default CounterReact将按照 effect 声明的顺序依次调用组件中的每一个 effect; 4.决定useEffect的执行次数 默认情况下useEffect的回调函数会在每次渲染都重新执行但是某些代码我们只是希望执行一次即可比如网络请求绑定事件、订阅redux。另外多次执行也会导致一定的性能问题。 我们如何决定useEffect在什么时候应该执行和什么时候不应该执行呢? useEffect实际上有两个参数 参数1回调函数上面已经提到了参数2一个数组表示该useEffect在哪些state发生变化时才重新执行(受谁的影响才会重新执行) 我们来看下面这个案例就明白了 import React, { memo } from react; import { useState, useEffect } from react;const Counter memo(() {let [counter, setCounter] useState(99);let [message, setMessage] useState(DJ drop);useEffect(() {//当前回调会在页面渲染完成后重新执行每次都重新执行document.title counter;console.log(counter的值变了我瞅见了)},[counter])useEffect(() {console.log(message的值改变了我瞅见了)},[message])useEffect(() {console.log(counter和message的值都变了我瞅见了)},[counter,message])return (divh2Counter{counter}/h2button onClick{() setCounter(counter 1)}点击让Counter1/buttonbutton onClick{() setMessage(the beat)}改变message/button/div) }) export default Counter在上面这个案例中页面第一次渲染每个useEffect都会先执行然后第一个useEffect只有当counter的值改变时会重新调用第二个useEffect只有当message的值改变时会重新调用第三个useEffect当counter和message的值任意一个改变时会重新调用。 当然啊如果要模拟生命周期如componentDidMount这种只在挂载时执行一次那么第二个参数写个空数组[]就行了表示我只调用第一次后面任何数据的修改都不会引起我的重新调用。 import React, { memo } from react; import { useState, useEffect } from react;const Counter memo(() {let [counter, setCounter] useState(99);useEffect(() {console.log(订阅了redux,绑定了某个事件A)return () {console.log(取消订阅redux,解绑某个事件A)}},[])useEffect(() {console.log(发送网络请求的逻辑)},[])return (divh2Counter{counter}/h2button onClick{() setCounter(counter 1)}点击让Counter1/button/div) }) export default Counter那么这样的话其实回调中返回值的那个回调也只有在组件即将销毁时调用相当于componentWillUnmount了非常奈斯。