目录
一、what is jsx?:
因为在react中,html代码其实是在函数式组件中return出来的,那么在其他的框架中都是写在标签中与函数方法等分离开的,所以jsx语法做的就是把html代码融入到JavaScript中来的。这样的好处是便于程序员的开发,实际交给浏览器编译之前还是会通过bable编译成纯JavaScript的。
比如在没有jsx的时候react是这样写的:
而有了jsx后是我们现在所用的写法,所以说jsx也就是一个createElement的语法糖。
二、react创建项目:
npx create-react-app (项目名)
三、react 路由:
1、路由传参,这里只说说编程式导航:
react函数式组件v6舍弃了很多以前的跳转api和withRoute,现在使用navigate进行跳转和返回。并且navigate跳转前面是不能加/斜杠的,那就变成把前面的忽略了,成了默认路径了。
①params传递参数:
params传递参数是需要在路由的path后面配置参数占位的,跳转的时候用斜杠/拼接变量,变量位置不能乱,要按照路由的拼接。
params接受参数:
②search传递参数:
search传递参数不需要在路由的path后面配置,跳转的时候开头用?中间用&运算符拼接变量。
search接受参数:
③state传递参数:
state接受参数:
传参小结:个人认为state虽然让地址栏变得好看,但是存在一些问题,如果把网址复制分享出去,别人通过url进来的时候页面会报错的,因为别人没有通过点击跳转,所以也收不到数据。
四、React Hooks:
1、useState:
react会对state数据进行整合更新,防止多次更改造成不必要的性能浪费,所以让人看起来像是异步的,其实是同步更新的,只不过react做了延迟而已。而且,在组件中你普通定义的变量会随着组件的一次次更新重新创建被重新定义,那么这个普通变量会一直被赋初始值,所以react用state来保存你对值的每次操作,且会让页面同时渲染,触发re-render。
2、useEffect:
Effect是react函数式组件的生命周期,有不同的写法模拟不同的生命周期。
3、useCallback:
众所周知,useState对你想更新的变量做了存储,让他有了记忆,但是当你用useState的set方法去更新了一个变量的时候,整个组件会被重新执行一次,虽然变量都被state记忆了,但是组件内部的函数并没有,所以当state被更新,函数体内的所有函数都会被重新定义一次,这是很耗费性能的,比如日期倒计时的时候,岂不是每秒钟都要重新定义组件内的所有函数了。
那么针对这个问题,react给出了useCallback这个hook给我们对函数进行一个缓存。
当你给 useCallback第二参数也就是数组里的变量,存放的是你这个函数需要用到的变量,才会在这个变量发生改变的时候重新定义此函数。其实就是把这个函数返回给你执行了,如果依赖变化,他会返回当前函数给你执行,但却不会替你执行噢!这是它和useMemo的区别!!!
4、useMemo:
那么上面有useCallback来缓存函数,那react怎么可能不照顾一下变量呢?useMemo相当于Vue里的计算属性,用来缓存结果的,它会返回一个计算后的结果给到你。
5、memo:
memo和useMemo是不一样的,memo用于包裹子组件;
可以看到,我把父组件的a变量+1,却导致了子组件的重新渲染,即便子组件接受的是b、c,并不是a,也还是渲染了。
import { memo } from "react";
function Go(props) {
console.log('儿子渲染了');
return(
<div>
<button>我是子组件+1</button>
</div>
)
}
export default memo(Go);//可以发现当子组件被memo包裹后,props没有变化的话是不会重新render的
可以看到,使用了memo包裹子组件后,不会出现不必要的渲染,因为memo会让组件的props进行一个比较,比较上一次的值和当前值是否发生变化,变化了再re-render。
6、useContext:
跨组件通信,让你避免的使用redux。
这是第一步创建:
这是第二步,确定提供者,在提供者里包裹数据:
这是第三步,消费者使用:
7、useRef:
第一种,起初的作用是做到对Dom 元素的引用,当我们想操作的原生 DOM 元素的时候,我们可以使用Ref 做到对元素的引用。useRef 每次都会返回相同的引用,不会随着组件的更新而重新创建,这是它与createRef的区别,createRef每次都会返回一个新的引用。useRef 不仅仅是用来管理 DOM ref 的,它还可以存放任何变量。
第二种,你可以通过useRef保存一个你的变量实现跨渲染存值,为什么这么说呢?
上回书说useState可以保存你每次对变量的操作不会因为组件更新而重新定义,但是state每次都会让页面重新渲染的哦!!!如果你有不必实时更新倒页面的变量,你完全可以使用useRef去创建变量,这对性能优化是很可观的。这就是useRef的跨渲染存值。例如:你有一个定时器,那么你可以用useRef去创建,这样从始至终定时器只被创建一次,销毁一次,不是很好嘛???
第三种,useRef还可以判断是初始渲染还是更新,通过判断useRef的current是否有值来实现,结合useEffect可以实现不执行Effect的第一次。
①forwardRef:
useref你可以把ref设置在dom元素上,但是当你想把它设置在函数式组件上是会报错的,因为函数式组件并没有实例,所以你要给函数子组件套上ref的话必须给子组件套上forwardref
forwardref可以实现一个ref转发,让父组件的ref可以访问到子组件里的ref。
②useImperativeHandle:
forwardref虽然可以访问子组件的ref但是太过于鸡肋了,我们可以用useImperativehandle直接从父组件访问子组件的方法,对这样不是更好吗?useImperativehandle自定义给父组件暴露的实例,在当前组件render后执行。
import logo from './logo.svg';
import './App.css';
import { useEffect,useRef } from 'react';
import Go from './go';
function App() {
const refc = useRef(null)
const kan =()=>{
console.log(refc);
refc.current.ggg()
}
return (
<div className="App" onClick={kan}>
<button>我是父组件+1</button>
<Go ref={refc}></Go>
</div>
);
}
export default App;
import { forwardRef, useImperativeHandle, useState } from "react";
function Go(props,ref) {
let [aa,setAa] = useState(0)
useImperativeHandle(ref,()=>{//第一个参数是父组件传递过来的ref,第二参数是一个回调函数返回一个对象,里面放你想传递的参数和方法
return{
ggg,
text:'我是儿子来的'
}
})
const ggg = ()=>{
setAa(aa+1)
}
return(
<div>
<button onClick={ggg}>我是子组件+1</button>
<h1>{aa}</h1>
</div>
)
}
export default forwardRef(Go);
最后useImperativehandle的第三个参数,也就是他的依赖项。空数组就只执行一次,不些的话每次render都执行,写了就是依赖变化去更新。个人觉得这个属性不错的。下面有个例子:
useImperativehandle可以传递变量,函数,也可以传递ref,非常的方便,所以不需要用到转发ref。
8、useReducer:
。。。
9、自定义hooks:
。。。