函数组件
内容 1.创建方式 2.函数组件没有state怎么办 3.函数组件没有生命周期怎么办 4.自定义hooks函数
函数组件的创建方式
两种形式
1' 声明一个变量等于箭头函数
const Hello = (props) => {
return <div>{props.message}</div>
}
const Hello = props => <div>{props.message}</div>
2' 使用function
function Hello(props){
return <div>{props.message}</div>
}
消除了this 函数组件能代替Class组件吗? 完全可以,但是目前不行,我们要学些新的东西,比如hooks API
函数组件代替Class组件
面临两个问题 1.函数组件没有state React v16.8.0推出Hooks API 其中的一个API叫做useState可以解决问题 2.函数组件没有生命周期 React v16.8.0推出Hooks API 其中的一个API叫做useEffect可以解决问题 useEffect(函数式编程的专有名词)是专门用来解决生命周期的问题的。
1.函数组件没有state怎么办? React提供了useState并提供读、写2个API,可以对数据进行读、写操作。 第1个参数是读,第2个参数是写,初始值为0。 需要引入useEffect或者直接React.useEffect
const App = props => {
const [n, setN] = React.useState(0)
const onClick = () => {
setN(n + 1)
}
return (
<div>{n}
<button onClick={onClick}> +1 </button>
</div>
)
}
函数组件模拟生命周期
什么叫生命周期? 当处于某个阶段时会有提醒要不要做什么事(渲染、挂载、更新、卸载)
用useEffect模拟3个重要的生命周期 一.通过useEffect模拟/实现第一次渲染 细节:useEffect默认每次渲染都会调用(只有1个参数),利用第2个参数[] 指明只在第1次渲染时调用该函数。
import React, { useEffect } from "react"
const App = props => {
const [n, setN] = React.useState(0)
const onClick = () => {
setN(n + 1)
}
console.log(n)
useEffect(() => {
console.log("use effect")
}, [])
return (
<div>{n}
<button onClick={onClick}>+1</button>
</div>
)
}
export default App
二.通过useEffect模拟/实现更新 细节:第2个参数填"要更新的"变量,比如在n更新时执行useEffect 1’ 只有1个变量时:
useEffect(() => {
console.log("n变了")
}, [n])
2’ 有多个变量时:
useEffect(() => {
console.log("n或者m变了")
}, [n, m])
等价于:
useEffect(() => {
console.log("state变了")
})
不写的意思是,任何一个state变化都会执行useEffect函数
三.通过useEffect模拟/实现组件将死 每次点击hide时打印'Child 销毁了' 逻辑: 在useEffect函数里return另外一个函数,return的函数就是要死的。
import React, { useEffect, useState } from "react"
const App = props => {
const [childVisible, setChildVisible] = useState(true)
const hide = () => {
setChildVisible(false)
}
const show = () => {
setChildVisible(true)
}
return (
<div>
{childVisible ? <button onClick={hide}>hide</button> : <button onClick={show}>show</button>}
{childVisible ? <Child /> : null}
</div>
)
}
const Child = props => {
useEffect(() => {
console.log("渲染或者变化了")
return () => {
console.log('Child 销毁了')
}
})
return ( <div>Child</div> )
}
细节 1.不能这样写:onClick={setChildVisible(false)} onClick只接收函数,setChildVisible(false)返回值是undefined,undefined赋给onClick,onClick有个屁用,基础不扎实不要瞎写。 2.show是用来做函数名的,不是用来做变量的。
其它生命周期怎么模拟?
模拟render:函数组件的return就是render,返回值就是render的返回值。 其它 1.当需要return复杂逻辑时,return可以直接返回一个函数,将复杂逻辑写在函数里:
注意:x一定要返回div! 在x返回div前可以做任何事情
标签名最好都大写,防止跟原生的标签冲突。
const X = () => {
return <div>x</div>
}
const App = props =>{
return X()
}
2.不光return x,我还return另外一个函数,把2个函数拼在一起: 标签名最好都大写,防止跟原生的标签冲突
const X = () => {
const n = 1+1
return <div>x</div>
}
const Y = () => {
const n = 1+1
return <div>y</div>
}
const App = props =>{
return <>
<X></X> <Y></Y>
</>
}
自定义hook
第1次初始化也算变化(undefined变为0),怎么做到从第2次变化才算变化呢?
思路:使用自定义hook函数
逻辑:useUpdate是如何排除第一次执行函数的呢? 把依赖array(fn,array) 放到它自己的依赖里,只要你的依赖一变就把count+1 一发现count>1 就会执行你的思路 count怎么收集到呢? 如果数组变化我就count+1
import React, { useState, useEffect } from "react"
const useUpdate = (fn, array) => {
const [count, setCount] = useState(0)
useEffect(() => {
setCount(x => x + 1)
}, array)
useEffect(() => {
if (count > 1) {
fn()
}
}, [count])
}
const App = props => {
const [n, setN] = React.useState(0)
const onClick = () => {
setN(n + 1)
}
useUpdate(() => {
console.log("n变了")
}, [n])
return (
<div> {n} <button onClick={onClick}>+1</button> </div>
)
}
export default App
??自定义hook注意事项: 1.使用自定义hook函数名必须以use开头。 React默认组件是使用的大写字母开头,而自定义Hook函数使用的是use开头。 2.n最好从外面传进来。n直接用也可以但是可能会有警告。
模块化,把useUpdate放到单独的文件里。 1.src目录下新建useUpdate.js,拷贝代码
import React, { useState, useEffect } from "react"
const useUpdate = (fn, array) => {
const [count, setCount] = useState(0)
useEffect(() => {
setCount(x => x + 1)
}, array)
useEffect(() => {
if (count > 1) {
fn()
}
}, [count])
}
export default useUpdate 导出
2.使用useUpdate组件
import React, { useState, useEffect } from "react"
import useUpdate from "./useUpdate"
const App = props => {
const [n, setN] = React.useState(0)
const onClick = () => {
setN(n + 1)
}
useUpdate(() => {
console.log("n变了")
}, [n])
return (
<div>{n}
<button onClick={onClick}>+1</button>
</div>
)
}
export default App
|