类组件与函数组件的区别
类组件可以定义自己的state,用来保存自己的内部状态,类组件有自己的生命周期,可以在对应的生命周期中完成对应的逻辑操作。在componentDidMount发送网络请求,在数据更新时可以调用componentDidUpdate生命周期,在状态发生改变只会重新执行render函数
类组件中产生的副作用需要在componentWillUmmount中清除,比如redux中手动调用subscribe
函数组件不可以,函数每次调用都会产生新的临时变量,函数组件被重新渲染时,整个函数都会被重新执行
memo的作用:类似于类组件的pureC,会对props进行浅层比较,如果发生更新就重新渲染,如果没有发生更新就不会重新渲染
hooks
需要在react中导入
使用hooks的原则
只能在函数最外层调用Hook。不要在循环、条件判断或者子函数中调用。
只能在React 的函数组件中调用Hook。不要在其他JavaScript 函数,如果需要做条件判断,则可以将判断放到hook的内部
hook的用法
useState
useEffect
import{useState,useEffect} from 'react'
function Test() {
const [num,setNum]= useState(1);
useEffect(() =>{
console.log('挂载完毕,更新完毕');
return ()=>{
console.log("卸载完毕");
}
},[])
useEffect(()=>{
console.log('num更新',num);
return()=>{
console.log("num更新前",num);
}
},[num])
return (
<button onClick={()=>setNum(num+1)}>
{num}
</button> );
}
export default Test;
useReducer
reducer个redux中使用的reducer用法类似
import { useReducer } from 'react'
const initState = { num: 0 }
function reducer(state, action) {
switch(action.type) {
case 'increment':
return { num: state.num + 1 }
case 'decrement':
return { num: state.num -1 }
default:
return state
}
}
function App() {
const [ state, dispatch ] = useReducer(reducer, initState ) // --> ([reducer], [初始值])
return (
<>
<h2>{state.num}</h2>
<button onClick={dispatch({type: 'increment'})}>++++++</button>
<button onClick={dispatch({type: 'decrement'})}>------</button>
</>
)
}
自定义hooks
本质上普通的函数结合hooks,返回一些可以用的数据
import { useState,useEffect } from "react";
function News() {
//开关 上一页没有加载过来,就不允许加载
const [flag,setFlag]=useState(true);
//新闻列表数据 默认是一个空数组
const [list,setList]=useState([])
//新闻是第page页
const [page,setPage]=useState(1)
//获取新闻信息
function getNews(){
fetch("http://dida100.com/mi/list.php?channel_id=hot&page="+page)
.then(res=>res.json())
.then(res=>{
// console.log(res);
//更新list
setList(list.concat(res.result))
setFlag(true);
})
}
//page变化就获取一次新闻
useEffect(()=>{
getNews();
},[page])
//检查是否可以下一页
function check(){
console.log("执行监听");
//获取最后一个节点item
var last = document.querySelector(".item:last-child");
//获取last距离浏览器顶部的高度
// getBoundingClientRect获取元素的边界 {left,right,bottom,top,width,height}
var top =last.getBoundingClientRect().top;
if(top<window.innerHeight&&flag){
//把page加1
setPage(page+1);
setFlag(false);
//从请求到页面渲染,到下一个last元素出现,只要页面滚动都符合条件
}
}
//挂监听flag的变化(默认监听一次)
useEffect(()=>{
//挂载获取一次新闻
//监听页面滚动
window.addEventListener("scroll",check);
//卸载移除页面监听 flag变化之前移除监听
return ()=>{
console.log("移除监听");
window.removeEventListener("scroll",check);
}
},[flag])
return <div>
<h1>新闻列表</h1>
{/* 渲染数据,item,index是自定义的,item.title,item.summary来自接口定义 */}
{list.map((item,index)=><div className="item" key={index}>
<h3>{item.title}</h3>
<p>{item.summary}</p>
<hr />
</div>)}
</div> ;
}
export default News;