react复习

组件
分为class组件和函数组件,函数组件时没有this的,并且会产生闭包的效应,也就是当我们在某一个时刻去设置一个setTimeout事件,然后改变value,发现
我们setTimeout里面还是以前的值(https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/)

CSS
class要用className={`test${...}`}  这样用字符串拼接起来
style是个obj style={{color:getColor()}}  

如果想使用局部的样式,那我们可以使用cssloader然后开启modules, 然后import style from "./style.module.css", className={style.test}

如果是css之间的互相依赖,那么可以使用.test{composes: import common from "./common.module.css"},然后就会直接被test所使用

react给事件传参,有两种方式
1.通过bind: OnClick = {this.handler.bind(this,1)}
2.通过函数包裹: onClick = {()=>{this.handler(1)}},这里需要注意的是,如果我们这样写,拿到的index是event,应该把箭头函数参数里面的index去掉
onClick={(index) => {
                            console.log(index)
                            this.onChange(index)
}}>
我们不要将事件立即执行

改变react函数中的this的3种方法:
1.在函数调用处使用bind(this)     2.在构造函数处使用bind(this)    3.使用箭头函数

setState是异步的,并且会合并多次操作
例如console.log(this.state.count);   //0
    this.setState(state=>{count:state.count ++})
    console.log(this.state.count);    //0
 setState是一层浅合并,只需要改变我们需要的属性就行了
如果属性是个对象,那么就要弄个新的拷贝来修改,例如this.setState(state=>{a:[...arr]}),否则子组件PureComponent就感受不到变化了

单一数据源
如果我们把父组件传来的东西放在了自己的state里面,然后父亲改变了,子组件也会感受不到,所以我们要全部使用父亲的数据(页面render了)

高阶组件和renderProps:
对于我们传入子组件的标签里面的东西,我们在组件中可以通过props.children来拿到,如果我们传入的是一个子节点,那么props.children就是一个
变量,如果是多个子节点,那么就是一个Array. 通过拿到这个children,我们就可以实现类似于Vue中的插槽的功能,当我们把父组件的render函数传到
子组件的标签中,然后传入子组件的state,那么就实现了renderProps,子组件中就直接显示render函数中返回的内容.这也就相当于子组件里面封装了
逻辑,然后把需要的给render函数即可

JSX的原理:
把<div id=1 class="c"><div/><div/></div>变成了createElement("div",{id:1,clss:"c"},createElement("div"),createElement("div"))
第一个参数是标签,第二参数是属性,后面的参数都是子组件,如果是<div>aa</div>,然后aa就是字符串直接作为第3个参数,
如果标签小写的话,那么就会认为是一个原生的dom标签

Hooks

hooks解决的问题:当有state里面有很多变量的时候,如果我们在各个生命周期里面去操作他们,他们就会分散在各个函数中,组件变的难以维护,
但是hooks可以针对各个变量来将逻辑写在一起,提高了可读性,并且可以通过自定义hook,提高了复用性.
并且hook可以通过es6的语法来避免变量名称的冲突,明确的知道那个变量来自哪个hook.

useRef://https://zhuanlan.zhihu.com/p/105276393
1.可以用来获取dom const buttonRef = useRef()
                  <button ref={buttonRef}>
                  console.log(buttonRef.current)     //拿到button这个dom
2.跨生命周期保存数据,可以记录timer的id,如果是一般的let属性变量,经过一轮渲染就没了,保存不住后面被赋的新值,
 并且createRef也是每次组件经过新的渲染之后也会变成新的引用,例如createRef()
而useRef只要不去主动给他设置,它的值和保存的引用永远不变化
3.绕过闭包陷阱,如果我们每次点击按钮,按钮触发setTimeout(()=>{alert(count),3000}),然后在这个3s内我们使用setCount(count + 1),然后3s后alert
会是个0,这是因为每次渲染,函数组件都重新执行了一次,而在这次的执行中,如果触发setTimeout,那么就产生了闭包,因为整个组件就是个函数,props被闭包在了
这个组件的函数里面,所以回调函数的值和当前的值是不一样的.如果想要获得最新的,那么我们可以用ref来代替,alert(countRef.current),
然后3s内每次都将countRef.current ++.但是如果嫌每次我们都去手动改变countRef.current有点麻烦的话,那么可以在useEffect中写上countRef.current = count,
这样每次count变化的时候都会自动执行.
4.让页面显示上一次的值,由于在useEffect中,相当于componentDidMount,然后在里面设置useRef的值,不会再次渲染页面,所以页面上显示的ref.current是上一次的

useEffect:
可以认为每次渲染都产生了一个快照,如果状态改变了而触发了n次渲染,那么就产生了n个状态,而每个render状态都拥有自己固定不变的state和props,这个就是
Capture Value特性.例如
useEffect(()=>{setTimeout(()=>{conosle.log(`${count}`)},3000)})    //这时候会发现,我们调用setCount(count+1),打印出来的都是一一对应的过去的值
这个原理其实跟setState差不多,都是因为闭包,比如说这个函数
let arr = []
function test(count){
    let fn = ()=>{
       setTimeout(()=>{console.log(count)},3000)
      }
  arr.push(fn)    //每次执行一次就把函数放到数组里面去
    }

useEffect的触发时机其实是在组件的dom渲染完毕之后,再去触发,也就是当我们setCount之后,然后
1.浏览器渲染DOM
2.清除上一次count=0的effect
3.运行这次的的effect.       //也就相当于把arr里面的函数都运行一遍,这时候会发现打印的都是那时候的数据.

这个原理在于当我们去执行最后去commit fiber.updateQueue的时候,有destroy先执行destroy,再把 effect.create拿出来执行,得到destroy然后给到这个effect上面
也就是effecte.destroy = effect.create()
然后这个effect就有了destroy属性,当我们触发渲染再执行updateEffect的时候,prevHook.effect就是pushEffect(hookEffectTag, create, destroy)
的第三个参数


useCallback:
如果一个函数经过了useCallback的封装,那么可以做为useEffect的依赖里面去,例如fn = useCallback(fn,[param]),然后当params变化了,fn的引用
也会变化,导致useEffect中重新触发该函数,这样貌似会比在useEffect中直接依赖param好,因为双方都更加内聚,
所以个人理解是对于函数,既可以使用useRef.current报错引用,也可以用useCallback来保存,但是后者可以根据依赖的变化而改变函数的引用

useState: //https://blog.csdn.net/qiwoo_weekly/article/details/108332478
当functionalcomponent render的时候,每次执行到一个hook,例如useState,都会创建一个hook对象放在后面,
hook的数据结构为{
    memoizedState,    //里面放着存储的数据,比如useState里面放着最新的data,useeffect里面放着最新的effect对象
    updateQueue,     //里面放着Update对象,里面有action和next
    next
}
当我们第一次调用做了3件事:1.用mountWorkInProgressHook方法创建一个hook,顺便把它追加到fiber的memoizedState后面,让workInProgressHook指向它
2.在hook上面设置memoizedState记录状态和设置queue  3.生成dispatch

第二次调用将指针WorkInProgressHook向后移动追加在后面,而当前的这个组件fiber节点会被放到一个全局的currentlyRenderingFiber.
let [count,setCount] = setSate(0)
而当我们用第二个参数setCount的时候,然后当组件重新渲染,它会又按照原来的链表顺序,把存起来的值拿出来给count,这就是为什么不能在if中使用hook,
setCount(count+1)的时候,其实这个count已经是新的值了,所以参数count+1是对的 
而返回来的第二参数其实是一个dispatchAction函数,这个dispatchAction在调用的时候,会bind(null,currentlyRenderingFiber,queue),这样也就是说
可以拿到queue,然后用户调用生成的dispacth,生成一个update对象,放入到queue中去,然后再scheduleRoot进入渲染.
当第二次进入这个fiber的时候会执行queue.forceUpdate


useReducer:
userReducer也可以解决useEffect的保存快照的问题,因为它相当于useState(c=>c+1)这种传了一个函数的管理模式,帮我们去操作数据,从而它
没有依赖任何外界的dep,所以可以解决这个问题.

useMemo:
只有当依赖变化了,才会重新执行,否则就使用缓存,跟useState一样,是在渲染期间就会执行(useEfffect,是最后commit才执行).
useCallback是返回函数
   


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值