函数式组件
名称以大写字母开头
渲染流程 : 执行了ReactDOM.render(
- React解析组件标签,找到了MyComponent组件。
发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
//1.创建函数式组件function MyComponent(){console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('test'))
hooks - V16.8版本以上
1. 什么是hooks
Hooks的本质:一套能够使函数组件更强大,更灵活的“钩子”
React体系里组件分为 类组件 和 函数组件
经过多年的实战,函数组件是一个更加匹配React的设计理念 UI = f(data),也更有利于逻辑拆分与重用的组件表达形式,而先前的函数组件是不可以有自己的状态的,为了能让函数组件可以拥有自己的状态,所以从react v16.8开始,Hooks应运而生
注意点:有了hooks之后,为了兼容老版本,class类组件并没有被移除,俩者都可以使用
- 有了hooks之后,不能在把函数成为无状态组件了,因为hooks为函数组件提供了状态
-
2. Hooks解决了什么问题
Hooks的出现解决了俩个问题 1. 组件的状态逻辑复用 2.class组件自身的问题
组件的逻辑复用在hooks出现之前,react先后尝试了 mixins混入,HOC高阶组件,render-props等模式但是都有各自的问题,比如mixin的数据来源不清晰,高阶组件的嵌套问题等等
class组件自身的问题class组件就像一个厚重的‘战舰’ 一样,大而全,提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this指向问题等等,而我们更多时候需要的是一个轻快灵活的’快艇’
hooks总结
hooks方法
useState- 获取state & setState
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法:const [xxx, setXxx] = React.useState(initValue)
(3). useState()说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
newValue需要通过计算才能获得时使用第二种写法export default function About() {const [count,setCount] = React.useState(0);const [list,setList] = React.useState([22]);function add(){//普通类型// setCount(count+1) //方法一setCount(count => count+1) //方法二//引用类型setList([...list,count])}return(<div><h2>当前求和为:{count}</h2><button onClick={add}>点我+1</button></div>)}
useEffect - 生命周期函数
什么是副作用
副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,**主作用就是根据数据(state/props)渲染 UI**,除此之外都是副作用(比如,手动修改 DOM)
常见的副作用
- 数据请求 ajax发送
- 手动修改dom
- localstorage操作
useEffect函数的作用就是为react函数组件提供副作用处理的!
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(3). 语法和说明:
注意:如果第三个参数不写则只要useState产生数据变化就会执行,相当于监听所有数据
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [依赖的状态]) // 如果指定的是[], 回调函数只会在第一次render()后执行,不为空则在该参数变化时才执行
(4). 可以把 useEffect Hook 看做如下三个函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
(5). useLayoutEffect (同步执行副作用) 使用方式与useEffect一样但调用时机不同,
useLayoutEffect 和原来 componentDidMount & componentDidUpdate 一致,
在react完成DOM更新后马上同步调用的代码,会阻塞页面渲染。而 useEffect 是会在整个页面渲染完才会调用的代码
useEffect执行时机
export default function About() {
const [count,setCount] = React.useState(0);
React.useEffect(()=>{
//componentDidMount
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
//componentWillUnmount
return ()=>{
clearInterval(timer)
}
},[count])//componentDidUpdate
}
Ref Hook - 获取ref
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样
export default function About() {
const myRef = React.useRef()
function show(){
console.log(myRef.current.value);
}
return(
<div>
<input type="text" ref={myRef}/>
<button onClick={show}>点我提示数据</button>
</div>
)
}
useCallback(记忆函数)
防止因为组件重新渲染,导致方法被重新创建 ,起到缓存作用; 只有第二个参数 变化了,才重新声明一次
//useCallback 不会执行第一个参数函数,而是将它返回给你 所以常用记忆事件函数,
//生成记忆后的事件函数并传递给子组件使用
var handleClick = useCallback((evt)=>{
console.log(name)
},[name])
<button onClick={()=>handleClick()}>hello</button>
//只有name改变后, 这个函数才会重新声明一次,
//如果传入空数组, 那么就是第一次创建后就被缓存, 如果name后期改变了,拿到的还是老的name。
//如果不传第二个参数,每次都会重新声明一次,拿到的就是最新的name.
useMemo 记忆组件
与 useCallback 唯一的区别是:useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并 且将函数执行结果返回给你。
所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数 计算得到一个确定的值,比如记忆组件。
//useMemo 更适合经过函数 计算得到一个确定的值
const getCinemaList = useMemo(
() => cinemaList.filter() //过滤出一个数组交给dom渲染
, [cinemaList])
return <div>
{
getCinemaList.map()
}
</div>
useContext (Provider)
可以减少组件层级传递数据
类似vue的provide 与 inject
import React, { useState,useEffect,useContext } from 'react'
import axios from 'axios'
import './css/index.css'
const GlobalContext = React.createContext() //创建context对象
export default function App (){
const [filmList, setfilmList] = useState([])
const [info, setinfo] = useState("")
useEffect(() => {
axios.get(`/test.json`).then(res=>{
// console.log(res.data.data.films)
setfilmList(res.data.data.films)
})
}, [])
return (
//包裹子组件 传递value
<GlobalContext.Provider value={{
call:"打电话",
sms:"短信",
info:info,
changeInfo:(value)=>{
setinfo(value)
}
}}>
<div>
{/* {this.state.info} */}
{
filmList.map(item=>
<FilmItem key={item.filmId} {...item} ></FilmItem>
)
}
//子组件
<FilmDetail ></FilmDetail>
</div>
</GlobalContext.Provider>
)
}
/*受控组件*/
function FilmItem(props){
let {name, poster,grade,synopsis} = props
//子组件获取value
const value = useContext(GlobalContext)
// console.log(context)
return <div className="filmitem" onClick={()=>{
//调用value
value.changeInfo(synopsis)
}}>
<img src={poster} alt={name}/>
<h4>{name}</h4>
<div>观众评分:{grade}</div>
</div>
}
function FilmDetail(){
//子组件获取value
const value = useContext(GlobalContext)
return <div className="filmdetail">
detail-{value.info}
</div>
}
useReducer (react自己的redux)
import React,{useReducer} from 'react'
//处理函数reducer
const reducer = (prevState,action)=>{
console.log("reduercer",prevState,action)
let newstate = {...prevState}
switch(action.type){
case "kerwin-minus":
newstate.count--
return newstate
case "kerwin-add":
newstate.count++
return newstate
default:
return prevState
}
}
// 外部的对象
const intialState = {
count:0,
// list:[]
}
export default function App() {
//接收两个参数1.处理函数 2.对象数据
const [state, dispatch] = useReducer(reducer,intialState)
return (
<div>
<button onClick={()=>{
//触发reducer
dispatch({
type:"kerwin-minus"
})
}}>-</button>
{state.count}
<button onClick={()=>{
//触发reducer
dispatch({
type:"kerwin-add"
})
}}>+</button>
</div>
)
}
useReducer和useContext 结合使用
通过useContext给后代传递useReducer的state和dispatch,完成多个组件对同一数据的使用和修改
import React, { useEffect,useContext,useReducer } from 'react'
import axios from 'axios'
import './css/index.css'
const GlobalContext = React.createContext() //创建context对象
const intialState ={
info:"",
filmList:[]
}
const reducer = (prevState,action)=>{
var newState = {...prevState}
switch(action.type){
case "change-filmlist":
newState.filmList = action.value
return newState
case "change-info":
newState.info = action.value
return newState
default :
return prevState
}
}
export default function App (){
const [state,dispatch] =useReducer(reducer,intialState)
useEffect(() => {
axios.get(`/test.json`).then(res=>{
// console.log(res.data.data.films)
dispatch({
type:"change-filmlist",
value:res.data.data.films
})
})
}, [])
return (
<GlobalContext.Provider value={
{
state,
dispatch
}
}>
<div>
{/* {this.state.info} */}
{
state.filmList.map(item=>
<FilmItem key={item.filmId} {...item} ></FilmItem>
)
}
<FilmDetail ></FilmDetail>
</div>
</GlobalContext.Provider>
)
}
/*受控组件*/
function FilmItem(props){
let {name, poster,grade,synopsis} = props
const {dispatch} = useContext(GlobalContext)
// console.log(context)
return <div className="filmitem" onClick={()=>{
console.log(synopsis)
// this.props.onEvent(synopsis)
// value.info = "2222222"
// console.log(value)
dispatch({
type:"change-info",
value:synopsis
})
}}>
<img src={poster} alt={name}/>
<h4>{name}</h4>
<div>观众评分:{grade}</div>
</div>
}
function FilmDetail(){
const {state} = useContext(GlobalContext)
return <div className="filmdetail">
detail-{state.info}
</div>
}
自定义hook-抽离可复用业务组件 - fetch获取数据
注意:
- hooks以use开头
- hooks是钩子函数 只能在函数组件实体内部调用,不能在函数体内调用,下图会报错 ```jsx import React, { useState,useEffect,useMemo } from ‘react’ import axios from ‘axios’
//自定义hook - 获取电影列表 function useCinemaList(){ const [cinemaList, setcinemaList] = useState([]) useEffect(() => { axios({ url:”https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=7406159“, method:”get”, headers:{ ‘X-Client-Info’: ‘{“a”:”3000”,”ch”:”1002”,”v”:”5.0.4”,”e”:”16395416565231270166529”,”bc”:”110100”}’,
'X-Host': 'mall.film-ticket.cinema.list'
}
}).then(res=>{
setcinemaList(res.data.data.cinemas)
})
}, [])
return {
cinemaList
}
} //自定义hook - 对电影列表数据进行过滤 function useFilter(cinemaList,mytext){ const getCinemaList = useMemo(() => cinemaList.filter(item=>item.name.toUpperCase().includes(mytext.toUpperCase()) || item.address.toUpperCase().includes(mytext.toUpperCase()) ), [cinemaList,mytext])
return {
getCinemaList
}
} //电影列表组件 export default function Cinema(){ const [mytext, setmytext] = useState(“”)//用于获取搜索电影关键字
const {cinemaList} = useCinemaList()//获取电影列表
const {getCinemaList} = useFilter(cinemaList,mytext)//获取电影过滤列表
return <div>
{/* {this.state.mytext} */}
<input value={mytext} onChange={(evt)=>{
setmytext(evt.target.value)
}}/>
{
getCinemaList.map(item=>
<dl key={item.cinemaId}>
<dt>{item.name}</dt>
<dd>{item.address}</dd>
</dl>
)
}
</div>
} ```
