react和vue对比
相同点
- MV*框架,
- 虚拟DOM(但diff算法不同),
- 专注于视图层
不同点
- API来说:vue提供了指令,以及拥有双向数据绑定等概念,react没有提供指令,但是用于受控组件和非受控组件的概念
- 性能优化来说:vue框架自动提供性能优化,手工优化(memo、useMemo、useCallback)
- 从文件上来说:vue是一种SFC(single file component)的方式,react是以
jsx这种方式
useState的使用
- 更新普通类型的数据
setState(123)
- 更新对象、对象的值
对象、数组引用类型值只要引用地址没有发生变化,状态就不会发生变化,页面也不会触发页面更新
// 更新数组
const [state,setState] = useState(['tom','lily'])
setState([...state,'anmy'])
// 更新对象
const [state,setState] = useState({name:'tom',age:18})
setState({...state,age:19})
- useState可以接收一个函数 这样可以减少计算,如果是useState(1+1),那么首次加载的时候1+1会被重新计算
let [n, setN] = useState(()=>1+1);
- setN也可以是个函数(推荐使用)
setN(n=>n+1);
如果不写函数会出现以下问题:当多次setN的时候只会执行最后一次,所以只加1了
let add = () => {
//只会加1,如果n不传递那么也会执行一次setN(()=>n+1)
setN(n+1);
setN(n+1)
};
如果想要批量更新可以使用函数的方式,函数必须使用要传递参数
setCount((count)=>count+1)
setCount((count)=>count+1)
setCount((count)=>count+1)
react17和react18对比
- 在 React 18 之前,React 事件处理程序期间批量更新。默认情况下,React 中不会批处理 Promise、setTimeout等的更新,React 18 所有的都会批量更新,这一定程度上减少了性能的损耗。 原文链接
react
useReducer的使用
是用来代替useState 1.创建初始值
let initVal = {
n: 1,
};
2.创建所有操作reducer
let reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.params };
} else if (action.type === "mul") {
return { n: (state.n *= action.params) }
}else{
throw new Error('没有对应的类型')
}
};
3.创建读和写API
let [state,dispatch] = useReducer(reducer,initVal)
4.调用写API
onClick={()=>dispatch({type:'add',params:2})}
完整代码如下:
import { useReducer } from "react";
let initVal = {
n: 1,
};
let reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.params };
} else if (action.type === "mul") {
return { n: (state.n *= 2) }
}else{
throw new Error('没有对应的类型')
}
};
function App() {
let [state,dispatch] = useReducer(reducer,initVal)
return (
<div>
state.n的值{state.n}
<button onClick={()=>dispatch({type:'add',params:2})}>+1</button>
</div>
);
}
useContext的使用
useContext个人理解是一个组件间快速传值的过程。如下代码是通过props父子传递参数,子组件再去更改父组件的状态。
//父组件
function Father() {
let [state,setState] = useState(0)
return (
<div>
这是父组件{state}
<Son value={{state,setState}}/>
</div>
);
}
//子组件
<button onClick={()=>{
props.value.setState(props.value.state+1)
}}>+1</button>
但是当父子组件层级非常多的时候props的方式显得非常臃肿,这时useContext就非常好用了。
1.创建上下文
const Context = React.createContext(null);
- 指定作用域
let [state,dispatch] = useState(0)
return (
<context.Provider value={{ state,dispatch }}>
<Father />
</context.Provider>
);
3.接收值(作用域范围都可以接收)
let { state, dispatch } = useContext(context);
onClick={()=>dispatch(state+10);
useEffect和useLayoutEffect的使用
useEffect(()=>{},[]) //第一次render时更新,相当于componentDidMount
useEffect(()=>{},[n]) //n的值发生变化时更新,包括第一次render的时候,如果第二个参数没有,
//所有数据都变化时更新
useEffect(()=>()=>{}) //传递一个函数,组件卸载之前更新相当于componentWillUnMount
useLayoutEffect要早于useEffect调用
优先使用useEffect,useLayoutEffect中加载的1000在页面还未渲染到页面时更新里面的值,不会产生闪烁的效果,但是会延迟页面的显示
useMemo的使用
用法
// calculateValue是一个函数用来计算更新的值(首次、依赖发生变化会调用该函数)
// dependencies是当依赖更新时会重新调用calculateValue
const cachedValue = useMemo(calculateValue, dependencies)
// 例子
const sum2 = useMemo(function(){
console.log('sum2被调用了')
const arr = Array.from({ length: 100 }).fill(1)
const data = arr.reduce((pre, next) => pre + next, 0)
return data
},[])
使用场景
-
跳过计算,避免多次计算,可以根据依赖来进行更新计算
-
避免组件不必要的更新
如下,当点击按钮时,会触发点击事件
handleState,会更新state的值,从而使得App组件被更新,由于组件Son嵌套在App组件中,也会引发更新,但是Son组件更新时不必要的更新
import { useState, useMemo } from 'react'
function App() {
const [state, setState] = useState("name")
const handleState = () => {
//处理状态
setState('我更新了状态')
}
return (
<>
<p>
{state}
</p>
<Son />
<button onClick={handleState}>
我是按钮
</button>
</>
)
}
function Son(){
console.log('我是Son组件,我被更新了')
return (<>
</>)
}
export default App
这种情况下可以使用memo来使得组件Son引发不必要的更新,在组件Son中使用memo来包裹,
import { useState, useMemo, memo } from 'react'
import './App.css'
function App() {
const [state, setState] = useState("name")
const handleState = () => {
//处理状态
setState('我更新了状态')
}
return (
<>
<p>
{state}
</p>
<Son />
<button onClick={handleState}>
我是按钮
</button>
</>
)
}
const Son = memo(function (){
console.log('我是Son组件,我被更新了')
return (<>
</>)
})
export default App
当父组件的状态更新时,并且子组件中的props是一个对象时,因为父组件中的状态发生更新,并且因为props地址指针发生变化,导致子组件发生更新,但是此时状态发生更新是不必要的
import { useState, useMemo, memo } from 'react'
import './App.css'
function App() {
const [state, setState] = useState("name")
const handleState = () => {
//处理状态
setState('我更新了状态')
}
const handleSon = () =>{
}
return (
<>
<p>
{state}
</p>
<Son handleSon={handleSon}/>
<button onClick={handleState}>
我是按钮
</button>
</>
)
}
const Son = memo(function ({handleSon}){
console.log('我是Son组件,我被更新了')
return (<>
<button onClick={handleSon}>
</button>
</>)
})
export default App
使用useMemo进行优化
import { useState, useMemo, memo } from 'react'
import './App.css'
function App() {
const [state, setState] = useState("name")
const handleState = () => {
//处理状态
setState('我更新了状态')
}
const handleSon = useMemo(() =>{
// return 要返回的值,这里是个函数
return () =>{
}
},[])
return (
<>
<p>
{state}
</p>
<Son handleSon={handleSon}/>
<button onClick={handleState}>
我是按钮
</button>
</>
)
}
const Son = memo(function ({handleSon}){
console.log('我是Son组件,我被更新了')
return (<>
<button onClick={handleSon}>
</button>
</>)
})
export default App
useRef
useRef用来存储同一个变量