网站名称和备案,如何做百度推广的网站,南宁网站推广费用,wordpress怎么自动手机版文章目录 Hooks概念理解什么是HooksHooks解决了什么问题 useState基础使用状态的读取和修改组件的更新过程使用规则回调函数作为参数 useEffect什么是函数副作用基础使用依赖项控制执行时机清理副作用发送网络请求 useRefUseContext Hooks概念理解 什么是Hooks
Hooks的本质一套能够使函数组件更强大更灵活的“钩子” 注意点
有了hooks之后为了兼容老版本class类组件并没有被移除俩者都可以使用有了hooks之后不能在把函数成为无状态组件了因为hooks为函数组件提供了状态hooks只能在函数组件中使用
Hooks解决了什么问题 Hooks的出现解决了俩个问题 1. 组件的状态逻辑复用 2.class组件自身的问题 组件的逻辑复用在hooks出现之前react先后尝试了 mixins混入HOC高阶组件render-props等模式但是都有各自的问题比如mixin的数据来源不清晰高阶组件的嵌套问题等等class组件自身的问题class组件就像一个厚重的‘战舰’ 一样大而全提供了很多东西有不可忽视的学习成本比如各种生命周期this指向问题等等而我们更多时候需要的是一个轻快灵活的’快艇’
useState 基础使用
作用
useState为函数组件提供状态state
使用步骤
导入 useState 函数调用 useState 函数并传入状态的初始值从useState函数的返回值中拿到状态和修改状态的方法在JSX中展示状态调用修改状态的方法更新状态
代码实现
import { useState } from reactfunction App() {// 参数状态初始值比如,传入 0 表示该状态的初始值为 0// 返回值数组,包含两个值1 状态值state 2 修改该状态的函数setStateconst [count, setCount] useState(0)return (button onClick{() { setCount(count 1) }}{count}/button)
}
export default App状态的读取和修改
读取状态 该方式提供的状态是函数内部的局部变量可以在函数内的任意位置使用 修改状态
setCount是一个函数参数表示最新的状态值调用该函数后将使用新值替换旧值修改状态后由于状态发生变化会引起视图变化
注意事项
修改状态的时候一定要使用新的状态替换旧的状态不能直接修改旧的状态尤其是引用类型 组件的更新过程
函数组件使用 useState hook 后的执行过程以及状态值的变化
组件第一次渲染 从头开始执行该组件中的代码逻辑调用 useState(0) 将传入的参数作为状态初始值即0渲染组件此时获取到的状态 count 值为 0 组件第二次渲染 点击按钮调用 setCount(count 1) 修改状态因为状态发生改变所以该组件会重新渲染组件重新渲染时会再次执行该组件中的代码逻辑再次调用 useState(0)此时 React 内部会拿到最新的状态值而非初始值比如该案例中最新的状态值为 1再次渲染组件此时获取到的状态 count 值为1
重点一句话useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说以后的每次渲染useState 获取到都是最新的状态值React 组件会记住每次最新的状态值
import { useState } from reactfunction App() {const [count, setCount] useState(0)// 在这里可以进行打印测试console.log(count)return (button onClick{() { setCount(count 1) }}{count}/button)
}
export default App使用规则 useState 函数可以执行多次每次执行互相独立每调用一次为函数组件提供一个状态 也就是每个状态互不影响 function List(){// 以字符串为初始值const [name, setName] useState(cp)// 以数组为初始值const [list,setList] useState([])
}useState 注意事项 只能出现在函数组件或者其他hook函数中不能嵌套在if/for/其它函数中只能在函数组件的最外层去调用react按照hooks的调用顺序识别每一个hooklet num 1
function List(){numif(num / 2 0){const [name, setName] useState(cp) }const [list,setList] useState([])
}
// 俩个hook的顺序不是固定的这是不可以的回调函数作为参数
使用场景
如果初始 state 需要通过计算才能获得则可以传入一个函数。参数也就是回调函数只会在组件的初始渲染中起作用后续渲染时会被忽略。
语法
const [name, setName] useState((){ // 编写计算逻辑 return 计算之后的初始值
})语法规则
回调函数return出去的值将作为 name 的初始值回调函数中的逻辑只会在组件初始化的时候执行一次
语法选择 3. 如果就是初始化一个普通的数据 直接使用 useState(普通数据) 即可 4. 如果要初始化的数据无法直接得到需要通过计算才能获取到使用useState((){})
例如我们来一个需求
import { useState } from reactfunction Counter(props) {const [count, setCount] useState(() {return props.count})return (divbutton onClick{() setCount(count 1)}{count}/button/div)
}function App() {return (Counter count{10} /Counter count{20} //)
}export default AppuseEffect 什么是函数副作用
什么是副作用 副作用是相对于主作用来说的一个函数除了主作用其他的作用就是副作用。对于 React 组件来说主作用就是根据数据state/props渲染 UI除此之外都是副作用比如手动修改 DOM 常见的副作用
数据请求 ajax发送手动修改domlocalstorage操作
useEffect函数的作用就是为react函数组件提供副作用处理的
你可以把useEffect看作是React生命周期方法的一种替代useEffect可以模拟componentDidMountcomponentDidUpdate和componentWillUnmount的行为。你可以在一个组件中使用多个useEffect以便将不同的副作用分开处理。useEffect是一个Hook所以你只能在组件的顶层或者你自定义的Hook中调用它不能在循环或条件语句中调用它。如果你不需要与外部系统同步你可能不需要使用useEffect。
基础使用
作用 为react函数组件提供副作用处理 使用步骤
导入 useEffect 函数调用 useEffect 函数并传入回调函数在回调函数中编写副作用处理例如dom操作修改数据状态检测副作用是否生效
import { useEffect, useState } from reactfunction App() {const [count, setCount] useState(0)useEffect((){// dom操作document.title 当前已点击了${count}次})return (button onClick{() { setCount(count 1) }}{count}/button)
}export default App依赖项控制执行时机
1.不添加依赖项
组件首次渲染执行一次以及不管是哪个状态更改引起组件更新时都会重新执行
组件初始渲染组件更新 不管是哪个状态引起的更新
useEffect((){console.log(副作用执行了)
})2.添加空数组
组件只在首次渲染时执行一次
useEffect((){console.log(副作用执行了)
},[])3.添加特定依赖项
副作用函数在首次渲染时执行在依赖项发生变化时重新执行
function App() { const [count, setCount] useState(0) const [name, setName] useState(zs) useEffect(() { console.log(副作用执行了) }, [count]) return ( button onClick{() { setCount(count 1) }}{count}/button button onClick{() { setName(cp) }}{name}/button / )
}注意事项
useEffect 回调函数中用到的数据比如count就是依赖数据就应该出现在依赖项数组中如果不添加依赖项就会有bug出现useEffect回调是在dom渲染之后执行useEffect和vue里的watch有点像但是执行时机是不同的
清理副作用
如果想要清理副作用 可以在副作用函数中的末尾return一个新的函数在新的函数中编写清理副作用的逻辑。
注意执行时机为
组件卸载时自动执行组件更新时下一个useEffect副作用函数执行之前自动执行
import { useEffect, useState } from reactconst App () {const [count, setCount] useState(0)useEffect(() {const timerId setInterval(() {setCount(count 1)}, 1000)return () {// 用来清理副作用的事情clearInterval(timerId)}}, [count])return (div{count}/div)
}export default App发送网络请求
使用场景
如何在useEffect中发送网络请求并且封装同步 async await操作
语法要求
useEffect中不能是一个异步函数的原因是useEffect的第一个参数应该是一个返回undefined或者一个清理函数的函数而不是一个返回Promise的函数。异步函数会返回一个Promise这个Promise不能被当作一个清理函数来调用。这样做会导致useEffect的行为不符合预期可能会出现内存泄漏或者数据不一致的问题。 正确写法
如果你想在useEffect中使用异步函数你有两种方法
在useEffect内部定义一个异步函数并立即调用它。在useEffect外部定义一个异步函数并在useEffect内部调用它。但是这样做的话你需要把这个异步函数放到useEffect的依赖数组中并且用useCallback来包裹它以防止不必要的调用。
useEffect(() {// 定义一个异步函数const fetchData async () {// 你可以在这里使用awaitconst response await MyAPI.getData(someId);// ...}// 立即调用这个异步函数fetchData();
}, [someId]); // 或者[]如果副作用不需要props或state
// 在useEffect外部定义一个异步函数并用useCallback包裹它
const fetchData useCallback(async () {// 你可以在这里使用awaitconst response await MyAPI.getData(someId);// ...
}, [someId]); // 这里的依赖项要和useEffect的一致useEffect(() {// 在useEffect内部调用这个异步函数fetchData();
}, [fetchData]); // 这里的依赖项要包含这个异步函数
useRef 使用场景
在函数组件中获取真实的dom元素对象或者是组件对象
使用步骤
导入 useRef 函数执行 useRef 函数并传入null返回值为一个对象内部有一个current属性存放拿到的dom对象组件实例通过ref 绑定要获取的元素或者组件
代码实现
获取dom
import { useEffect, useRef } from react
function App() { const h1Ref useRef(null) useEffect(() { console.log(h1Ref) },[]) return ( div h1 ref{ h1Ref }this is h1/h1 /div )
}
export default App获取组件实例 函数组件由于没有实例不能使用ref获取如果想获取组件实例必须是类组件 class Foo extends React.Component { sayHi () { console.log(say hi) } render(){ return divFoo/div }
}export default Fooimport { useEffect, useRef } from react
import Foo from ./Foo
function App() { const h1Foo useRef(null) useEffect(() { console.log(h1Foo) }, []) return ( div Foo ref{ h1Foo } //div )
}
export default AppUseContext UseContext的作用是让你在组件中使用ContextContext是一种在组件树中传递数据的方式它可以让你在不使用props的情况下让深层嵌套的组件访问一些全局的状态。使用UseContext的步骤如下
首先你需要使用createContext创建一个Context对象并给它一个默认值。然后你需要使用Context.Provider组件包裹你的组件树并给它一个value属性这个value就是你要传递的数据。最后你可以在任何子组件中使用useContext(Context)来获取这个value这样你就可以在组件中使用这个数据了。
使用UseContext的好处是你不需要通过props来一层一层地传递数据这样可以避免一些不必要的渲染和复杂的逻辑。你也可以在Context中存储一些函数以便在组件中调用它们。使用UseContext的注意事项是你需要保证你使用的Context对象是同一个否则你可能会得到undefined的值。你也需要注意useContext的依赖关系如果你的Context的value发生变化那么所有使用了这个Context的组件都会重新渲染除非你使用了memo或者useMemo来优化性能。
代码实现
import { createContext, useContext } from react
// 1.创建Context对象
const Context createContext()function Foo() { return divFoo Bar//div
}function Bar() { // 3.底层组件通过useContext函数获取数据 const name useContext(Context) return divBar {name}/div
}function App() { return ( // 2.顶层组件通过Provider 提供数据 Context.Provider value{this is name} divFoo//div /Context.Provider )
}export default App同时我们们还可以使用Context机制完成依赖注入
Context是React提供的一种在组件树间传递数据的方法它可以让我们避免通过中间元素传递props从而简化组件的结构和逻辑。Context的设计目的是为了共享那些对于一个组件树而言是“全局”的数据比如主题、语言、用户信息等。
依赖注入是一种编程理念它可以让我们将依赖的对象或者服务从外部注入到组件中而不是让组件自己创建或者寻找。依赖注入可以提高代码的可测试性、可重用性和可维护性同时也降低了组件之间的耦合度。
在React中我们可以使用Context机制来实现依赖注入的效果即将需要共享的数据或者逻辑封装在一个Context对象中然后在组件树的上层使用Provider组件来提供这个Context对象再在下层的组件中使用Consumer组件或者useContext Hook来消费这个Context对象。这样我们就可以在不同的组件中访问和操作同一个Context对象而不需要通过props来传递。
一个简单的例子是我们可以创建一个ThemeContext对象用来存储主题相关的数据比如颜色、字体等。然后在根组件中使用ThemeContext.Provider来提供这个对象并在子组件中使用ThemeContext.Consumer或者useContext(ThemeContext)来获取这个对象。这样我们就可以在子组件中根据主题的数据来渲染不同的样式而不需要从根组件一层一层地传递主题的数据。代码如下
// 创建一个ThemeContext对象
const ThemeContext React.createContext({color: black,font: Arial
});// 根组件
function App() {// 使用ThemeContext.Provider来提供ThemeContext对象return (ThemeContext.Provider value{{color: blue, font: Helvetica}}div classNameAppHeader /Content //div/ThemeContext.Provider);
}// 子组件
function Header() {// 使用useContext(ThemeContext)来获取ThemeContext对象const theme useContext(ThemeContext);// 根据ThemeContext对象来渲染样式return (div classNameHeader style{{color: theme.color, font: theme.font}}h1React Context Example/h1/div);
}// 子组件
function Content() {// 使用ThemeContext.Consumer来获取ThemeContext对象return (div classNameContentThemeContext.Consumer{theme (// 根据ThemeContext对象来渲染样式p style{{color: theme.color, font: theme.font}}This is some content with theme./p)}/ThemeContext.Consumer/div);
}注意
在上面的代码中我们可以看到React.createContext中指定了一个对象。这是为了给这个Context对象设置一个默认值。默认值是当组件树中没有匹配的Provider时组件读取到的Context的值。默认值可以是任何类型不一定是对象但是对象可以包含多个属性方便我们在Context中存储和传递更多的数据。默认值只是作为一个“最后的备选方案”它是静态的不会随着时间而改变。如果我们想要动态地改变Context的值我们需要在组件树的上层使用Provider组件来提供Context的值。也就是说useContext会有优先从Provider的value中找如果找不到就会从createContext方法传递过来的默认参数中找。