[React] 函数组件
创建一个函数组件
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | const Hello = (props) => {return <div>{props.message}</div>
 }
 
 const Hello = props => <div>{props.message}</div>
 
 function Hello(props){
 return <div>{props.message}</div>
 }
 
 | 
Hooks
useState
- 
setN一定会触发重新渲染
 
- 
数据会被存入新的n 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | function App() {const [n, setN] = React.useState(0);
 return (
 <div className="App">
 <p>{n}</p>
 <p>
 <button onClick={() => setN(n + 1)}>+1</button>
 </p>
 </div>
 );
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | function App() {const [n, setN] = useState(0)
 const onClick = ()=>{
 setN(n+1)
 setN(n+1)
 
 
 }
 return (
 <div className="App">
 <h1>n: {n}</h1>
 <button onClick={onClick}>+2</button>
 </div>
 );
 }
 
 | 
useReducer
Flux/Redux思想
useState的复杂版,常用于表单
- 
创建初始值 
- 
创建操作合集reducer(state,action) 
- 
传给useReducer,得到读写API 
- 
调用写API,传一个type ({type:‘操作类型’}) 
代替Redux
- 
将数据集中在一个store对象 
- 
将操作集中在reducer 
- 
创建一个Context 
- 
创建对数据的读写api 
- 
将读写api放入Context 
- 
用Context.Provider把api提供给所有组件 
- 
各个组件用useContext获取读写api 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | const initial = {n: 0
 };
 
 const reducer = (state, action) => {
 if (action.type === "add") {
 return { n: state.n + action.number };
 } else if (action.type === "multi") {
 return { n: state.n * 2 };
 } else {
 throw new Error("unknown type");
 }
 };
 
 function App() {
 const [state, dispatch] = useReducer(reducer, initial);
 const { n } = state;
 const onClick = () => {
 dispatch({ type: "add", number: 1 });
 };
 const onClick2 = () => {
 dispatch({ type: "add", number: 2 });
 };
 return (
 <div className="App">
 <h1>n: {n}</h1>
 <button onClick={onClick}>+1</button>
 <button onClick={onClick2}>+2</button>
 </div>
 );
 }
 
 | 
useContext
上下文,相当于在某一范围中充当「全局变量」的作用
从上至下逐级更新的过程,不是响应式过程(监听数据变化并做出反应)
- 
创建一个Context | 1
 | const C = createContext(null)
 |  
 
- 
用C.Provider圈定范围 | 12
 3
 4
 5
 
 | <C.Provider value={}>const [ n, setN ] = useState(0)
 <ComponentA />
 <ComponentB />
 </C.Provider>
 
 |  
 
- 
在组件中使用 | 1
 | const { n, setN } = useContext(C)
 |  
 
useEffect
每次render后调用的函数
在函数组件中,作为componentDidMount, componentDidUpdate, componentWillUnmount使用
多个useEffect会按写代码时的先后顺序执行
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | useEffect(() => {})  
 useEffect(() => {}, [])
 
 useEffect(() => {}, [n])
 
 
 useEffect(() => { return () => {}})
 
 
 | 
useLayoutEffect
在浏览器改变外观前执行,区别于useEffect在浏览器改变外观之后
因此useLayoutEffect总是比useEffect先执行
useMemo
React.memo(ComponentA): ComponentA只在props更新后执行
| 12
 3
 
 | const fn = useMemo(() => {return () => {}
 }, [m,n])
 
 | 
缓存内容,在页面刷新时缓存上一次的值,并使新渲染的组件使用该缓存值,新fn和旧fn为相同的两个空函数。只有m或者n变化时,fn才会重新得到新值
如果不使用useMemo,两次得到的fn会因为函数地址不同而被认为是两个不同的函数,从而触发组件的渲染,增加了渲染量,降低了性能
useCallback
useMemo简化版
| 1
 | const fn = useCallback(() => {}, [m,n])
 | 
useRef
让一个值在组件不断render时保持不变
| 12
 3
 4
 5
 
 | const count = useRef(0)
 useEffect(()=>{
 count.current += 1
 })
 
 | 
此时count记录了组件渲染的次数
使用.current的原因是:使用引用,来确保每次的渲染得到的新count都是指向同一个对象的引用
注意:count.current的变化不会触发UI的更新,需要调用useState来手动更新
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | const [随便取一个,set随便取一个] = useState(null)
 const onClick = () => {
 count.current += 1
 set随便取一个(Math.random())
 }
 
 
 
 
 | 
forwardRef
React的函数组件需要使用forwardRef来获取外部传来的ref
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | function App() {const buttonRef = useRef(null)
 return(
 <div>
 <Button2 ref={buttonRef}>button</Button2>
 </div>
 )
 }
 
 const Button2 = React.forwardRef((props,ref) => {
 return (<button ref={ref} {...props} />)
 }
 
 | 
useImperativeHandle
自定义ref