1.useState
import React, { useState } from 'react'
const ClickCount = () => {
const [count, setCount] = useState(0)
const [info, setInfo] = useState({ name: 'wq', age: 0 })
const handleClick = () => {
setCount(count+1)
setInfo({ ...info, age: info.age + 1 })
}
return (
<div>
<p>count: {count}</p>
<p>age: {info.age}</p>
<button onClick={handleClick}>+1</button>
</div>
)
}
2.useEffect:相当于函数周期componentDidMonut和componentDidUpdate
(1)情况1
const Fetch = () => {
const [result, setResult] = useState(null)
// 会打印两次,第一次是因为componentDidMonut,第二次是因为setResult导致触发componentDidUpdate
useEffect(()=>{
setResult('会打印辆次')
})
return (
<div>
result: {result}
</div>
)
}
(2)情况2:解决情况1的问题,只想让useEffect执行一次
const Fetch = () => {
const [result, setResult] = useState(null)
// 不添加任何依赖
useEffect(()=>{
setResult('会打印一次')
}, [])
return (
<div>
result: {result}
</div>
)
}
(3)情况3:可以添加多个依赖,当其中一个依赖发生变化时都会触发useEffect
const Fetch = () => {
const [result, setResult] = useState(null)
const [result1, setResult1] = useState(null)
useEffect(()=>{
setResult('111')
setResult1('121')
}, [result, result1])
return (
<div>
result: {result}
result1: {result1}
</div>
)
}
(4)情况4:为了防止useEffect中会使用capture value,必须加上依赖,不然每次都会显示1,因为每次拿到的数据count都是0
import React, { useState, useEffect } from 'react'
const Fetch = () => {
const [count, setCount] = useState(0)
useEffect(()=>{
const timer = setInterval(() => {
setCount(count+1)
}, 1000);
// 每次依赖发生变化时触发改方法
return () => clearInterval(timer)
}, [count])
return (
<div>
count: {count}
</div>
)
}
3.useRef
(1)使用useRef解决上面capture value的问题
import React, { useState, useEffect, useRef } from 'react'
const Fetch = () => {
const [count, setCount] = useState(0)
const countRef = useRef(0)
useEffect(() => {
countRef.current = count
}, [count])
useEffect(()=>{
const timer = setInterval(() => {
// 此时拿到的countRef.current就是最新的count值
setCount(countRef.current+1)
}, 1000);
return () => clearInterval(timer)
}, [])
return (
<div>
count: {count}
</div>
)
}
(2)使用useRef获取DOM给元素绑定事件
import React, { useState, useEffect, useRef } from 'react'
const Fetch = () => {
const [count, setCount] = useState(0)
const btnRef = useRef(null)
useEffect(() => {
const handleClick = () => setCount(count+1)
btnRef.current.addEventListener('click', handleClick, false)
return () => btnRef.current.removeEventListener('click', handleClick, false)
}, [count])
return (
<div>
count: {count}
<button ref={btnRef}>+1</button>
</div>
)
}
4.memo, useMemo:避免不需要的组件渲染,以达到优化的效果
(1)情况1:使用memo在改变父组件的状态时,自组件不会重新渲染
import React, { useState, memo } from 'react'
const Child = memo(() => {
const date = new Date()
return (
<div>当前时间:{date.getHours()}:{date.getMinutes()}:{date.getSeconds()}</div>
)
})
const Parent = () => {
const [ count, setCount ] = useState(0)
return (
<div>
count: {count}
<button onClick={()=> setCount(count+1)}>+1</button>
<Child />
</div>
)
}
(2)情况2:使用memo当父组件改变子组件中的状态时,子组件才会渲染
import React, { useState, memo } from 'react'
const Child = memo((props) => {
const { count } = props
const { age } = count
const date = new Date()
return (
<div>当前时间:{date.getHours()}:{date.getMinutes()}:{date.getSeconds()} {age}</div>
)
})
const Parent = () => {
const [ count, setCount ] = useState(0)
const [ clickTimeCount, setClickTimeCount ] = useState({age: 1})
return (
<div>
count: {count}
<button onClick={()=> setCount(count+1)}>+1</button>
<button onClick={()=> setClickTimeCount({...clickTimeCount, age: clickTimeCount.age+1})}>更新时间</button>
<Child count={clickTimeCount} />
</div>
)
}
(3)知识点:memo的第二个参数控制是否渲染,当为false的时候才会渲染,为true的时候不渲染
const Child = memo((props) => {
const { count } = props
const { age } = count
const date = new Date()
return (
<div>当前时间:{date.getHours()}:{date.getMinutes()}:{date.getSeconds()} {age}</div>
)
}, (prev, next) => {
console.log(prev, next)
// 当return为true的时候不会渲染,为false的时候才会渲染
return false
})
5.useCallback
import React, { useState, memo, useCallback } from 'react'
const Child = memo((props) => {
const date = new Date()
return (
<div>
当前时间:{date.getHours()}:{date.getMinutes()}:{date.getSeconds()}
<input onChange={props.onChange} />
</div>
)
})
const Parent = () => {
const [ count, setCount ] = useState(0)
const [text, setText] = useState('')
const [ clickTimeCount, setClickTimeCount ] = useState(0)
const onChange = useCallback(
(e) => {
setText(e.target.value)
},
[],
)
return (
<div>
count: {count}
text: {text}
<button onClick={()=> setCount(count+1)}>+1</button>
<button onClick={()=> setClickTimeCount(clickTimeCount+1)}>更新时间</button>
<Child onChange={onChange} />
</div>
)
}
6.自定义hooks
import { useEffect, useState } from 'react'
const useWindowSIze = () => {
const [width, setWidth] = useState(0)
const [height, setHeight] = useState(0)
useEffect(() => {
setWidth(document.documentElement.clientWidth)
setHeight(document.documentElement.clientHeight)
}, [])
useEffect(() => {
const onRise = () => {
setWidth(document.documentElement.clientWidth)
setHeight(document.documentElement.clientHeight)
}
window.addEventListener('resize', onRise, false)
return ()=> window.removeEventListener('resize', onRise)
}, [])
return [width, height]
}
export default useWindowSIze
import useWindowSIze from './hooks'
const Parent = () => {
const [width, height] = useWindowSIze()
return (
<div>
size: {width}*{height}
</div>
)
}
7.useReducer、useContext
(1)useReducer
import React, { useReducer, useContext } from 'react'
const reducer = (state, action) => {
switch (action.type) {
case "ADD": return state + 1;
case "SUB": return state - 1;
default: return state
}
}
const Child = () => {
const [count, dispatch] = useReducer(reducer, 10)
return (
<div>
child:
count: { count}
<button onClick={() => dispatch({ type: 'ADD' })}>+1</button>
<button onClick={() => dispatch({ type: 'SUB' })}>-1</button>
</div>
)
}
(2)useContext
import React, { useReducer, useContext } from 'react'
const Ctx = React.createContext(null)
const reducer = (state, action) => {
switch (action.type) {
case "ADD": return state + 1;
case "SUB": return state - 1;
default: return state
}
}
const Child = () => {
const [count, dispatch] = useContext(Ctx)
return (
<div>
child:
count: { count}
<button onClick={() => dispatch({ type: 'ADD' })}>+1</button>
<button onClick={() => dispatch({ type: 'SUB' })}>-1</button>
</div>
)
}
const Parent = () => {
const [count] = useContext(Ctx)
return (
<div>
parent: {count}
<Child />
</div>
)
}
const User = () => {
const [ count, dispatch ] = useReducer(reducer, 20)
return (
<Ctx.Provider value={[count, dispatch]}>
<Parent />
</Ctx.Provider>
)
}
8.useSelect、useDispatch代替connect
目录结构:
component
action.js (1)
Form.js (2)
reducer.js (3)
store
configureStore.js (4)
reducer.js (5)
App.js (6)
index.js (7)
(1)
export const TYPE = {
UPDATA_NAME: 'UPDATA_NAME',
UPDATA_TEL: 'UPDATA_TEL'
}
export const updateTel = (tel) => ({
type: TYPE.UPDATA_TEL,
payload: {
tel
}
})
export const updateName = (name) => ({
type: TYPE.UPDATA_TEL,
payload: {
name
}
})
(2)
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateName, updateTel } from './action'
export default () => {
const dispatch = useDispatch()
const formData = useSelector(state => {
return state.formReducer
})
console.log('formData', formData)
return (
<div>
姓名: <input onChange={(e)=> {dispatch(updateName(e.target.value))}} /> <br />
电话: <input onChange={(e)=> {dispatch(updateTel(e.target.value))}} />
</div>
)
}
(3)
import { TYPE } from './action'
const initState = {
tel: '',
name: ''
}
export default (state, action) => {
const { type, payload } = action
if(Object.values(TYPE).includes(type)) return {...state, ...payload}
return state || initState
}
(4)
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import reducer from './reducer'
export default () => {
const middlewares = [thunk]
const enhancers = applyMiddleware(...middlewares)
const composedEnhancers = composeWithDevTools(...[enhancers])
const store = createStore(reducer, composedEnhancers)
return store
}
(5)
import { combineReducers } from 'redux'
import formReducer from '../components/reducer'
export default combineReducers({
formReducer
})
(6)
import React from 'react'
import Form from './components/Form'
const App = () => {
return (
<Form />
)
}
export default App
(7)
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import App from './App'
const store = configureStore()
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)