import React, {useState, useEffect } from 'react';
/**
*
* useState():在函数中提供state数据
*
* useEffect():
* The Effect Hook lets you perform side effects in function components:
* side effects :副作用 容易造成副作用的污染*作:网络请求,事件监听 dom*作
*
* class 组件: 有生命周期函数钩子 方便处理 副作用*作
*
* class 组件
* 01 生命周期臃肿
* 02 逻辑复用
* 继承:不支持的多继承
* 渲染:组件嵌套 性能差
* 03 this 指向
*
*/
// 01 需求:组件在状态更新的时候 改变 document.title
// class App extends React.Component{
// constructor(props){
// super(props)
// this.state={
// count:0
// }
// }
// // 1.2 we typically want to perform our effects after React has updated the DOM.
// // This is why in React classes, we put side effects into componentDidMount and componentDidUpdate.
// componentDidMount(){
// console.log('componentDidMount');
// document.title= `You clicked ${this.state.count} times`
// }
// componentDidUpdate(){
// console.log('componentDidUpdate');
// document.title= `You clicked ${this.state.count} times`
// }
// // 1.1 In React class components, the render method itself shouldn’t cause side effects.
// // It would be too early
// render(){
// return (
// <div>
// <p>You Clicked {this.state.count} times</p>
// <button onClick={()=>this.setState({count:this.state.count+1})} >Click me</button>
// </div>
// )
// }
// }
// 1.3 useEffect() 解决需求
//代码复制: we have to duplicate(不得不复制) the code between these two lifecycle methods in class.
// This is because in many cases we want to perform the same side effect regardless of whether the component just mounted, or if it has been updated.
// 没有render after方法: we want it to happen after every render — but React class components don’t have a method like this.
// 抽离代码 也需要复制:We could extract a separate method but we would still have to call it in two places.
// Now let’s see how we can do the same with the useEffect Hook.
// 02 useEffect() 每次render之后 直接使用副作用*作
// function App(props){
// const [count,setCount] = useState(0)
// // 2.1 使用
// useEffect(()=>{
// document.title=`you click ${count} times`
// })
// return (
// <div>
// <p>You Clicked {count} times</p>
// <button onClick={()=>setCount(count+1)} >Click me</button>
// </div>
// )
// }
// 2.1 使用理解
// Tip:If you’re familiar with React class lifecycle methods,
// you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined
// 2.2 useEffect 做了什么
// render 后做点事情(副作用函数); 传递函数;
// 调用函数 :call it later after performing the DOM updates
// 其他事情:ocument title, but we could also perform data fetching or call some other imperative API.
// 2.3 useEffect 为什么在组件中使用
// 能够有效的访问state变量或者props:Placing useEffect inside the component lets us access the count state variable (or any props) right from the effect.
// 函数作用域的支持: We don’t need a special API to read it — it’s already in the function scope
// 2.4 Does useEffect run after every render?
// 默认是的: it runs both after the first render and after every update
// “mounting” and “updating” =>“after render”
// 3.0 释放资源、回收机制
// 一般情况:cleanup
// 特殊情况:订阅额外资源
// 危险 内存泄漏 memory leak
// class App extends React.Component{
// constructor(props){
// super(props)
// this.state={
// count:0,
// width:document.body.clientWidth
// }
// }
// resizeWidth=()=>{
// this.setState({
// width:document.body.clientWidth
// }
// )
// }
// componentDidMount(){
// document.title= `You clicked ${this.state.count} times`
// window.addEventListener('resize',this.resizeWidth,false)
// }
// componentDidUpdate(){
// document.title= `You clicked ${this.state.count} times`
// }
// componentWillUnmount(){
// window.removeEventListener('resize',this.resizeWidth,false)
// }
// render(){
// return (
// <div>
// <p>You Clicked {this.state.count} times</p>
// <p>body client width {this.state.width} </p>
// <button onClick={()=>this.setState({count:this.state.count+1})} >Click me</button>
// </div>
// )
// }
// }
// 04 useEffect() 返回函数
// function App(props){
// const [count,setCount] = useState(0)
// const [width,setWidth] = useState(document.body.clientWidth)
// const resizeWidth=()=>{
// setWidth(document.body.clientWidth)
// }
// // 设计 绑定资源和释放资源在一起使用 通过return函数
// // 符合 after render ,每次render 之后都会调用
// // 问题 : 每次render 之后 不应该都进行一次绑定和解绑
// // useEffect() 需要 componentDidMount(),componentWillUnmount()进行*作
// useEffect(()=>{
// window.addEventListener('resize',resizeWidth,false)
// console.log('addEventListener');
// return ()=>{
// console.log('removeEventListener');
// window.removeEventListener('resize',resizeWidth,false)
// }
// })
// // 每次render之后 就会调用
// //相当于 componentDidMount, componentDidUpdate
// useEffect(()=>{
// document.title=`you click ${count} times`
// })
// return (
// <div>
// <p>You Clicked {count} times</p>
// <p>body client width {width} </p>
// <button onClick={()=>setCount(count+1)} >Click me</button>
// </div>
// )
// }
// useEffect() 参数解决:第二个参数
function App(props){
const [count,setCount] = useState(0)
const [width,setWidth] = useState(document.body.clientWidth)
const resizeWidth=()=>{
setWidth(document.body.clientWidth)
}
// 问题 : 每次render 之后 不应该都进行一次绑定和解绑
// useEffect() 需要 componentDidMount(),componentWillUnmount()进行*作
// 解决 :第二个参数 传入一个空数组[],只会调用一次componentDidMount(),componentWillUnmount()
useEffect(()=>{
window.addEventListener('resize',resizeWidth,false)
console.log('addEventListener');
return ()=>{
console.log('removeEventListener');
window.removeEventListener('resize',resizeWidth,false)
}
},[])
// 第二个参数什么都不传:每次render之后 都会调用
//相当于 componentDidMount, componentDidUpdate
// useEffect(()=>{
// console.log('重新设置标题:count 点击了或者重新改变尺寸了');
// document.title=`you click ${count} times`
// })
// 只有点击时候 count 改变 的时候 才设置标题;尺寸改变 不影响 设置标题
// 解决 :第二个参数 传入一个空数组[变量] 只有变量变化了 才能触发 副作用*作执行
useEffect(()=>{
console.log('重新设置标题:第一次mouned 或则 count 点击');
document.title=`you click ${count} times`
},[count])
return (
<div>
<p>You Clicked {count} times</p>
<p>body client width {width} </p>
<button onClick={()=>setCount(count+1)} >Click me</button>
</div>
)
}
export default App;