useState + useEffect
语法:
const [state, setState] = useState(initialState);
useEffect(() => {},deps)
function App() {
const [width, setWidth] = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const handleWindowResize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};
useEffect(() => {
window.addEventListener('resize', handleWindowResize);
return () => window.removeEventListener('resize', handleWindowResize); //如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它
},[]);
// useCallback(() => {}, []);
// useMemo(() => {}, []);
// 三者中都有第二个参数,若第二个参数代表的依赖项发生变化则重新渲染,不执行则不渲染更新。
// useEffect在dom改变之后触发。
// useMeno在dom改变之前触发;父传方法给子时,子随着父的改变渲染多次,useMeno会将这些方法缓存起来,当第二个参数改变时才改变;它返回一个值;(不要在这个useMemo函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo)。
// useCallBack类似于useMeno,但如果传入props包含函数时,传递的函数即使内容一样还是会重新渲染,于是引入了useCallBack将props里面的函数也缓存起来;它返回一个函数,子组件一般配合meno使用。
return (
<>
<div className="App">
<header className="App-header">
<p>width: { width }</p>
<p>height: { height }</p>
</header>
</div>
</>
);
}
useMemo+useCallBack+memo性能优化
import { memo, useCallback, useMemo, useState } from "react"
const Son = memo(({ useInfo, clickChange }) => {
console.log('Son render')
return (
<>
<div>
Sonname: {useInfo.name}
<hr />
Sonage: {useInfo.age}
</div>
</>
)
})
const Parent = () => {
const [name, setName] = useState('react hooks');
const [count, setCount] = useState(0);
// useMemo缓存数据
const useInfo = useMemo(() => {
return {name, age: 18};
}, [name])
// useCallBack缓存函数
const clickChange = useCallback(() => {
console.log('clickChange')
}, [])
console.log('Parent render')
return (
<>
<Son useInfo={useInfo} clickChange={clickChange} />
<button onClick={() => setCount(count + 1)}>Parentclick</button>
</>
)
}
export default Parent;
useContext
语法:
const context = React.createContext(null);
const contextData = useContext(context);
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemesContext = React.createContext(themes.light); //设置light为初始值
function App() {
return (
<>
<div className="App">
<header className="App-header">
<ThemesContext.Provider value={themes.dark}>
<MiddleComp />
</ThemesContext.Provider>
</header>
</div>
</>
);
}
function MiddleComp() {
return (
<Son />
)
}
function Son() {
const theme = useContext(ThemesContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
)
}
useReducer
语法:
const [state, dispatch] = useReducer(reducer, { count: initialCount});
const reducer = (state: { count: number; }, action: { type: string; payload?: any; }) => {
switch(action.type) {
case 'increase':
return {count: state.count + 1};
case 'decrease':
return {count: state.count - 1};
case 'reset':
return {count: action.payload};
default:
throw new Error();
}
};
const Counter = ({initialCount} : any) => {
const [state, dispatch] = useReducer(reducer, { count: initialCount});
return (
<>
<p>Counter: {state.count}</p>
<button onClick={() => dispatch({type: 'reset', payload: initialCount})}>reset</button>
<button onClick={() => dispatch({type: 'increase'})}>+</button>
<button onClick={() => dispatch({type: 'decrease'})}>-</button>
</>
)
}
function App() {
return (
<>
<div className="App">
<header className="App-header">
<Counter initialCount={0} />
</header>
</div>
</>
);
}
useRef
语法:
const xxref = useRef(null)
const GetInputValue = () => {
const inputRef:any = useRef(null);
const [value1, setValue1] = useState('');
const [value2, setValue2] = useState('');
const getValue1 = (e:any) => {
setValue1(e.target.value);
};
const getValue2 = () => {
setValue2(inputRef.current?.value);
};
return (
<>
<input type="text" onChange={(e) => getValue1(e)}/>
<p>获取input1值: {value1}</p>
<input type="text" ref={inputRef}/>
<p>获取input2值: {value2}</p>
<button onClick={getValue2}>获取input2值</button>
</>
)
};
useImperativeHandle + forwardRef(父取子值)
const InputRef = (props:any) => {
const { label, myRef } = props;
const [value, setValue] = useState('');
const inputRef:any = useRef(null);
const handInputChange = (e:any) => {
setValue(e.target.value)
};
const getValue = () => {
return value
};
useImperativeHandle(myRef, () => ({
getValue,
focus() {
inputRef.current.focus()
},
}));
return (
<>
{label}:<input type="text" ref={inputRef} value={value} onChange={(e) => handInputChange(e)}/>
</>
)
};
const GetInputRef = forwardRef((props:any, ref:any) =>
<InputRef {...props} myRef={ref} />
);
const GetSon = () => {
const myRef:any = useRef(null);
const [value, setValue] = useState('');
const handleFocus = () => {
myRef.current.focus()
};
const getValue = () => {
setValue(myRef.current.getValue())
};
return (
<>
<GetInputRef label="name" ref={myRef}/>
<button onClick={handleFocus}>focus</button>
<span>{value}</span>
<button onClick={getValue}>getValue</button>
</>
)
};
function App() {
return (
<>
<div className="App">
<header className="App-header">
<GetSon />
</header>
</div>
</>
);
}
import React, { useEffect, useState, useContext, useReducer, useCallback, useMemo, useRef, useImperativeHandle, forwardRef } from 'react';
一个简单的自定义hooks
import { useState } from "react";
const useCounter = (init:number = 0) => {
const [count, setCount] = useState(init);
const decrease = (deCount:number = 1) => {
setCount(preCount => preCount - deCount)
};
const increase = (inCount:number = 1) => {
setCount(preCount => preCount + inCount)
};
return {count, decrease, increase}
};
export default useCounter;
import useCounter from './hooks/useCounter';
function App() {
const { count, decrease, increase } = useCounter(10);
const handleDecrease = () => {
decrease(2);
};
const handleIncrease = () => {
increase()
};
return (
<>
<div className="App">
<header className="App-header">
count:{count}
<button onClick={handleIncrease}>decrease+1</button>
<button onClick={handleDecrease}>increase-2</button>
</header>
</div>
</>
);
}
export default App;
ps: setState 有两种类型的参数。
//直接接收下一个状态作为参数的接口。
setState(newState);
//一个接口,它接受一个参数,从以前的状态计算一个新的状态。
setState((prev) => createNewStateFromPrevState(prev));