知识体系四:可能很多写法已经过时 不用跟着敲,看第五篇结合官方demo 文章定位:使用useState等方法构建无状态函数组件,不走Redux流程;
一、实践笔记来自:React Hooks 免费视频教程(共11集) (jspang.com)
- 特征:用函数的形式代替原来的继承类的形式,并且使用预函数的形式管理
state; - 有状态组件和无状态组件都可以使用函数式function,不用extends Component;
- 代替以前的redux写法
第一节 React Hooks介绍和环境搭建
- 计数器conut与对应set方法 hooks的useState设置与改变状态
import React, { useState } from 'react';
function Example(){
const [ count , setCount ] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
)
}
export default Example;
第二节 useState介绍与多状态声明
1、useState是react自带的一个hook函数,它的作用是用来声明状态变量。
- 数组解构,建立映射 并确定从0开始
- useState(0)地址对应count,useState(1)对应setCount
- 此时代码中通过{count}可以直接拿到值
2、 多状态声明
const [ age , setAge ] = useState(18)
const [ sex , setSex ] = useState('男')
const [ work , setWork ] = useState('前端程序员')
return (
<div>
<p>JSPang 今年:{age}岁</p>
<p>性别:{sex}</p>
<p>工作是:{work}</p>
</div>
)
第三节 useEffect代替常用生命周期函数(异步)
//首次渲染生命周期
componentDidMount(){ console.log(`ComponentDidMount=>You clicked ${this.state.count} times`) }
//第二次渲染生命周期
componentDidUpdate(){ console.log(`componentDidUpdate=>You clicked ${this.state.count} times`) }
//首次与第二次渲染生命周期都会走这个
useEffect(()=>{ console.log(`useEffect=>You clicked ${count} times`) })
第四节 useEffect 实现 componentWillUnmount生命周期函数解绑
- 渲染销毁时的生命周期:启用第二参数【当前状态值变化时触发生命周期,传[]为销毁时解绑,会执行return方法】
- 传空数组时就可以触发useEffect组件将被销毁时才进行解绑
- 比较有意思的是 传[count]后count变化这个就会触发
function Index() {
useEffect(()=>{
console.log('useEffect=>老弟你来了!Index页面')
return ()=>{
console.log('老弟,你走了!Index页面')
}
},[])
return <h2>JSPang.com</h2>;
}
第五节 useContext 让父子组件传值更简单[useContext和useReducer]
1、问题原因:在用类声明组件时,父子组件的传值是通过组件属性和props进行的,那现在使用方法(Function)来声明组件,已经没有了constructor构造函数也就没有了props的接收,那父子组件的传值就成了一个问题
2、 useContext和redux的作用是不同的,一个解决的是组件之间值传递的问题,一个是应用中统一管理状态的问题,但通过和useReducer的配合使用,可以实现类似Redux的作用
3、 实践
- 定义createContext对象,通过Provider展开value,允许跨层级实现传递和使用了(也就是实现了上下文),当父组件的
count变量发生变化时,子组件也会发生变化 - 补充好文:React Hooks 系列之3 useContext
import React, { useState , createContext } from 'react';
//===关键代码
const CountContext = createContext()
function Example4(){
const [ count , setCount ] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
{/*======关键代码 */}
<CountContext.Provider value={count}>
</CountContext.Provider>
</div>
)
}
export default Example4;
- 使用useContext接收传递过来的对象即可
function Counter(){
const count = useContext(CountContext) //一句话就可以得到count
return (<h2>{count}</h2>)
}
- 留意,这个是在同个文件夹中写个子组件取值
第六节 useReducer增强reducer
- useReducer参数1:reducer函数 参数2:状态初始值,会返回两个值
- const定义数组接收两个值,第一个是return的值,第二个是lambda派发器的地址
import React, { useReducer } from 'react';
function ReducerDemo(){
const [ count , dispatch ] =useReducer((state,action)=>{
switch(action){
case 'add':
return state+1
case 'sub':
return state-1
default:
return state
}
},0)
return (
<div>
<h2>现在的分数是{count}</h2>
<button onClick={()=>dispatch('add')}>Increment</button>
<button onClick={()=>dispatch('sub')}>Decrement</button>
</div>
)
}
export default ReducerDemo
第七,八节 useReducer代替Redux小案例
1、 useContext共享值
useContext:可访问全局状态,避免一层层的传递状态。这符合Redux其中的一项规则,就是状态全局化,并能统一管理。useReducer:通过action的传递,更新复杂逻辑的状态,主要是可以实现类似Redux中的Reducer部分,实现业务逻辑的可行性。
- 里面的共享颜色组件
- 我去这种写法还能嵌套也是服了,这tm还能传子组件。。因为要确定类型直接用这个:props.children。。强
import React, { createContext } from 'react';
export const ColorContext = createContext({})
export const Color = props=>{
return (
<ColorContext.Provider value={{color:"blue"}}>
{props.children}
</ColorContext.Provider>
)
}
2、使用useReducer管管理事件分发
第九节 useMemo优化React Hooks程序性能
1、问题:以前讲过TODOList的时候 讲道理shouldCompnentUpdate可以制止父组件更新时的子组件更新,现在 hook不再区分mount和update两个状态
- 解决方案:
useMemo(缓存属性/状态)和useCallback(缓存方法)都是解决上述性能问题的
2、 案例:父组件有发生变化时,所有子组件都会执行,这边点击运行就会给赋值一个新的时间戳,点第二个的时候,小红时间戳没变但也执行了
- 使用useMemo()
()=>changeXiaohong(name),[name]
- 第一个参数是个函数(用个箭头表达式子表面是函数 没左边那个是个方法结果)
()=>changeXiaohong(name) - 第二个参数是观察对象,当观察对象发生变化时执行这个函数,name是
<ChildComponent name={xiaohong}>{zhiling}</ChildComponent>传过来的小红对象,此时点小红才会执行。
第十节 useRef获取DOM元素和保存变量
1、作用
- 用
useRef获取React JSX中的DOM元素,获取后你就可以控制DOM的任何东西了。但是一般不建议这样来作,React界面的变化可以通过状态来控制。
- 用
useRef来保存变量,这个在工作中也很少能用到,我们有了useContext这样的保存其实意义不大,可以了解一下。
第十一节 自定义Hooks函数获取窗口大小[默认use开头]
1、导包
import React, { useState ,useEffect ,useCallback } from 'react';
2、编写函数
- 通过useState暴露属性
- useCallback(缓存方法)进行优化
- 渲染时声明监听'resize'屏幕发生尺寸变化,监听view解绑时销毁监听
function useWinSize(){
//size对象{width,width}
const [ size , setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})
//定义setSize方法 使用useCallback包裹 并返回给onResize对象
const onResize = useCallback(()=>{
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
//使用生命周期 渲染的时候执行onResize对象对应的方法
useEffect(()=>{
window.addEventListener('resize',onResize)
//使用return 方法销毁时解绑,取消监听
return ()=>{
window.removeEventListener('resize',onResize)
}
},[])
return size;
}
- 编写组件
function Example9(){
const size = useWinSize()
return (
<div>页面Size:{size.width}x{size.height}</div>
)
}
export default Example9
- Index.js引入即可看到页面大小,此时拖拽页面大小即可看到效果。
补充知识
一、 ES6语法
1、三种声明方式 var,let,const
1、 var为全局声明
var a=2;
{
var a=3;
}
console.log(a);//a=3
- let局部变量声明,出作用域立刻失效;
- 循环体内也很好用
for(let i=0;i<10;i++){ console.log('循环体中:'+i); }
- const声明常量
2、变量解构赋值
1、 数组的结构赋值
-
常见写法:
letl [a,b,c]=[1,2,3]; -
允许默认值:
let [a,b="JSPang"]=['技术胖'] console.log(a+b); //控制台显示“技术胖JSPang” -
注意的是undefined和null,undefined是啥都不干,相当于2中的写法(多参情况就好用),null是赋为null。
2、对象的解构赋值:String类型,对象外面用花括号
- 直接定义
let {foo,bar} = {foo:'JSPang',bar:'技术胖'};
console.log(foo+bar); //控制台打印出了“JSPang技术胖
- 若对象已声明,需要用圆括号全包裹
let foo;
({foo} ={foo:'JSPang'});
console.log(foo); //控制台输出jspang
3、 字符串解构:const [a,b,c,d,e,f]="JSPang";