1.useState,setState
区别: useState不会自动合并更新对象,想要合并更新对象可以使用函数式结合运算符:
useState(prevState => { // 也可以使用 Object.assign return {...prevState, ...updatedValues}; });
useState 初始state的时候可以是任意的数据类型,setState初始state的时候state只能是对象;setState改变某个state的后,会将之前其他的state和改变后的这个state合并更新。
this.setState(((prevState, props)=>{ return { count: prevState.count+1 } })) 或 this.setState({count: this.state.count+1})
相同点:setState,useState拿到最新的state后,重新渲染页面,页面展示最新的数据状态。
(“监听”数据变化,然后重新渲染页面,这里应该用到了观察者模式)
function useState (state, setState) { const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const setState = (state)=>{ listeners.forEach((listener) => listener()) return state } return {getState, setState , subscribe} } function setState(newState){ return newState } const state= useState(state, setState) state.subscribe(() => renderApp(state.getState())) // 监听数据变化 renderApp(state.getState()) // 首次渲染页面 state.useState(newSTate) // n次渲染
const [data, setData] = useImmer([{key:'account',value:1}]) setData(draft=>{ const obj = {key:'pwd',value:1} draft.splice(1,0,obj) }) const [data, setData] = useState([{key:'account',value:1}]) setData(preState=>{ const obj = {key:'pwd',value:1} return [obj, ...preState] }) data // [{key:'account',value:1},{key:'pwd',value:1}]
2.useRef
A)函数组件不同于class组件,class组件对不用于页面渲染的参数,可以用this机制存储起来。如:用来获取接口的参数
this.fetchParms ={pageIndex:1, pageSize:30} const tableData = { rowKey: (r, i) => `dayReport${i.toString()}`, dataSource: tableList.records, columns: nextColumns, pagination: { current: tableList.current, total: tableList.total, pageSize: 30, size: 'small', showTotal: (total) => `共 ${total} 条数据`, onChange: (pageIndex, pageSize) => { this.fetchParms ={pageIndex, pageSize} this.fetchList(dailyWorkReportListApi); }, }, loading: { spinning, tip: '加载中...' }, };
fetchList = (xxApi)=>{ xxApi(this.fetchParms).then(res=>{ this.setState({tableList: res.result || {}}) // 初始为{}对象的目的是为了防止遇到如20001等状态的的时候,后端不返回result健而报错
})
}
函数组件 设置初始值const fetchParms ={pageIndex:1, pageSize:30} ,后续在上面onChange函数中 fetchParms.pageIndex =pageIndex;fetchParms.pageSize = pageSize修改。若组件重新渲染(useState等)后,fetchParms 会回到初始值并没有保存他的修改。这时候设置初始值的时候需要用到useRef,不会出现这种现象。
const fetchParms = useRef({}) fetchParms.current = {pageIndex:1, pageSize:30} onChange函数中 fetchParms.current = {pageIndex, pageSize} fetchList(xxApi){ xxApi(fetchParms.current).then(res=>{ useState(res.result || {}) // 初始为{}对象的目的是为了防止遇到如20001等状态的的时候,后端不返回result健而报错 }) }
B)普遍操作,用来操作dom
const btnRef = useRef(null) <input ref={btnRef}>click me </button> btnRef.current.focus()
3.useEffect
useEffect(()=>{},[deps]),执行副作用操作,如果依赖项是[],和componentDidMount作用一样,如果返回一个函数,防止内存泄漏,清除函数会在组件卸载前执行。另外,如果组件多次渲染(通常如此),则在执行下一个 effect 之前,上一个 effect 就已被清除。如果依赖项是[]则和
4.useMemo
const memoizedValue = useMemo(() => { ...执行某些操作 return value; },[deps]);
依赖deps不发生改变,就会保留之前的memoizedValue的值,
把“创建”函数和依赖项数组作为参数传入 useMemo
,它仅会在某个依赖项改变时才重新计算 memoizedValue 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
记住,传入 useMemo
的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect
的适用范畴,而不是 useMemo
。
5.useCallback
const showDetail= useCallback( (value) => { ...执行某些操作 }, [deps], ); const columns = [{ title: '新增候选人总量', dataIndex: 'candidateTotal', width: 130, align: 'center', render: (text, record) => <a onClick={() => showDetail(12, record)}>{text}</a>, }],
返回一个 memoized 回调函数。
把内联回调函数及依赖项数组作为参数传入 useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate
)的子组件时,它将非常有用。
6.useContext
const MyContext = createContext({})
useContext 等同于static contextType = MyContext或 <MyContext.Consumer>{value=>{}}</MyContext.Consumer>。它的值仍然取的是离他最近的<MyContext.Provider value={}>中value的值
7.useState的异步回调
useState是异步的,没有回调。可以通过useEffect监听到数据的改变,再去执行同步的操作。
const [selectedGroupName, setSelectedGroupName] = useState({}) function handleSearch(fieldsValue, businessInfo){ setSelectedGroupName(businessInfo.linesName) } useEffect(()=>{ fetchList(xxxApi, {flag: true}) },[selectedGroupName]) function fetchList(api, obj){ api(fetchParams).then(res=>{ if(obj.flag){ behaviorReports('report_search', 'dailyReport', fetchParams, selectedGroupName); //工作日报行为监控 } }).catch(()=>{ message.error('error'); }) }