useState组件内部状态管理
import {useState} from 'react'
const App = () => {
const [n, setN] = React.useState(0);
return (
<div> <p>n:{n}</p>
<button onClick={()=>setN(n+1)}>+1</button>
</div>
)
}
useState hook返回两个值,第一个值是获取当前的状态值,第二个值是修改状态值的方法。useState是一个一集函数,能够记住状态的值。
useEffect
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await axios(
'http://localhost/api/v1/search?query=redux',
);
setData(result.data);
const timer = setInterval(()=>{
console.log("111")
},1000);
return () => {
timer = null;
}
},[]);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}x
- useEffect第二个参数是一个数组,当是一个空数组时,则只会在dom更新之后执行一次useEffect函数,当不是一个空数组的时候,每次依赖改变时,useEffect里定义的函数会再次被执行。
- useEffect的返回函数会在组件销毁的时候执行,如一些定时器就可以在这里进行删除。如果useEffect有依赖的情况下,会在每次更新的时候,销毁函数也会被执行。
- useEffect支持写多个,不同处理逻辑放在多个useEffect里面,结构会更加清晰
useLayoutEffect
useLayoutEffect(async () => {
const result = await axios(
'http://localhost/api/v1/search?query=redux',
);
setData(result.data);
const timer = setInterval(()=>{
console.log("111")
},1000);
return () => {
timer = null;
}
},[]);
-
useLayoutEffect和useEffect使用方法一致,不同的是,useEffect会在页面渲染完成之后再执行,useLayoutEffect仅在dom完成之后马上调用同步的代码,会阻塞页面渲染。
dom完成只是内存中已经存在对应dom结构,但是还没有渲染到页面上。 -
因为useEffect会在页面渲染完成之后再去执行,如果useEffect有操作dom或者动画等操作,引起回流重绘,可能会引起页面抖动的情况,所以为了避免这种情况可以使用useLayoutEffect,但是一般情况下,使用useEffect就可以。
useCallback
const A = ({ onClick }) => {
// A 父组件的count变化时,A组件仍旧会不断的re-render
console.log("case2: render_A");
return <button onClick={onClick}>A组件+count</button>;
};
export default function Case2() {
const [count, setCount] = useState(0);
const onClick = useCallback(() => {
setCount((count) => count + 1);
}, [count]);
return (
<>
<p>count:{count}</p>
<A onClick={onClick} />
</>
);
}
useCallback是记忆函数,当组件中的某些状态被改变的时候,如果没有使用useCallback,那么所有的函数都会被重新创建,但是有时候某些函数并不需要重新被渲染,所以就用到了useCallback,useCallback第二人参数为一个数组依赖,当为空的时候,onClick函数会一直被缓存,不会被重新渲染,只有当依赖改变的时候,才会重新创建。
useMemo
export default () => {
let [isChild, setChild] = useState(false);
return (
<div>
<Child isChild={isChild} name="child" />
<button onClick={() => setChild(!isChild)}>改变Child</button>
</div>
);
}
let Child = (props) => {
let getRichChild = () => {
console.log('rich child');
return 'rich child';
}
let richChild = useMemo(() => {
//执行相应的函数
return getRichChild();
}, [props.name]);
return (
<div>
isChild: {props.isChild ? 'true' : 'false'}<br />
{richChild}
</div>
);
}
useMemo也是一个记忆函数,可以完全代替useCallback函数,useCallback不会执行第一个参数函数,而是直接将函数返回给你,但是useMemo会执行它的第一个函数参数,并讲执行结果返回给你。useMemo的主要所用是执行逻辑,只有在某些依赖改变的时候,去计算对应的逻辑,然后将结果进行返回。
useRef
const RenderCounter = () => {
const counter = useRef(0);
// counter.current的值可能增加不止一次
counter.current = counter.current + 1;
return (
<h1>`The component has been re-rendered ${counter.current} times`</h1>
);
}
-
函数组件中useRef和createRef使用方法一致。
-
useRef与createRef最大的不同是,createRef每次重新渲染的时候都会创建一个新的ref对象,useRef第一次渲染创建一个对象之后,再重新渲染的时候,如果发现这个对象已经创建过就不会再创建第二次,性能会好一些,所以useRef一个重要的作用就是保存变量。
useContext
useContext在createContext的基础上,只是对子组件的使用方式进行了简化,两种使用方式比较如下:
//context消费者原来的方式
function Content() {
return (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
);
}
//context消费者使用useContext的方式
function Counter(){
const count = useContext(CountContext) //得到count
return (<h2>{count}</h2>)
}
useReducer
const initstate = 0;
const reducer = (state,action)=> {
if(action === 'add'){
return state + 1;
}
return state;
};
export default function ReducerDemo() {
const [ç, dispath] = useReducer(reducer, initstate);
return (
<div>
<h1 className="title">{count}</h1>
<button className="btn is-primary"
onClick={()=> dispath('add')}
>Increment</button>
</div>
)
}
useReducer最大的作用的将ui和数据状态管理分离开,initstate是初始化状态,reducer对状态进行管理,组件中内部使用直接使用count获取状态,使用dispath调用触发状态的修改。
自定义hook,
自定义hook,就是将某些组件中复杂的逻辑抽离封装成为一个函数,为什么一定要用use开头呢?因为不使用use,函数中有些hook就无法使用。
const useList = () => {
const [state, setState] = useState(initialState);
const deleteLi = (index) => {
setState((state) => {
const newState = JSON.parse(JSON.stringify(state));
newState.splice(index, 1);
return newState;
});
};
return { state, setState, deleteLi };//返回查、改、删
};