react 项目构建
webpack
npx create-react-app my-app
vite
yarn create @vitejs/app my-app
npm init @vitejs/app my-vue-app
react
state
惰性初始化state
const [initState,setinitState]=useState(()=>{return initData})
// 获取最新state
setinitState((nowState)=>{return nowState+1})
react18之前
在事件处理函数内部的 setState 是异步的;promise.settimeout,原生事件中setState在内是同步的
react18
默认所有 setState 是异步的。
state的异步是按批处理状态,不是真正的异步
强制立即更新状态,函数内部的多个 setState 仍然为批量更新
import { flushSync } from 'react-dom';
flushSync(() => {
setCount(count + 1);
});
props==vue prop
this.prop.ParentAttributes
hook
必须在最外层函数(组件)使用
state hook
const [state, setState] =useState("初始值")
effect hook
useEffect(){
}
自定义hook
useMyEffect(){
return [state,setState]
}
context
发送
export const MyContext = React.createContext(defaultValue);
<MyContext.Provider value={/* 某个值 */}>
接收
import { MyContext } from "../index";
MyContext.Consumer._currentValue;
发送
import {useContext,createContext} from 'react'
const MyContext = createContext(defaultValue);
<MyContext.Provider value={/* 某个值 */}>
</MyContext.Provider>
接收
useContext(MyContext)
refs
在组件重新渲染后,不会改变,设置current不会引起重新渲染
// 传递refs
const myRef = useRef(null)
const node = myRef.current;
render() {
return <div ref={myRef} />;
}
获取未来帧的值
function Example() {
const [count, setCount] = useState(0);
const currentCount = useRef(count);
currentCount.current = count;
const handleClick = () => {
// 延迟3秒,取得未来帧的count
setTimeout(() => {
setCount(currentCount.current + 1);
}, 3000);
};
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>
setCount
</button>
<button onClick={handleClick}>
Delay setCount
</button>
</div>
);
}
获取过去帧的值
function Example4() {
const [count, setCount] = useState(1);
const prevCountRef = useRef(1);
// 保存前一个count
const prevCount = prevCountRef.current;
// 设置最新count
prevCountRef.current = count;
const handleClick = () => {
setCount(prevCount + count);
};
return (
<div>
<p>{count}</p>
<button onClick={handleClick}>SetCount</button>
</div>
);
}
hooks闭包陷阱
使用hooks,dps数组未正确使用
// 组件完全渲染后执行,==vue onMounted
useeffrct(()=>{
return setinterval(fn,1000)
},[])
// 组件layout之后,patting之前,==vue onBeforeMounted
useLayoutEffect(()={},[])
React.memo
接受到的属性不变,则不重新渲染函数,减少组件渲染次数,需要封装成单独的组件
React.memo
memo()
useMemo
把创建函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算
useMemo(()=>({number}),[number]);
return []解构赋值当作useCallBack使用
const [a,b] = useMemo(()=>({return [a,b]}),[number]);
useCallback
接收一个内联回调函数参数和一个依赖项数组(子组件依赖父组件的状态,即子组件会使用到父组件的值) ,useCallback 会返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
useCallback(()=>{setNumber(number+1);},[number]);
useReducer
useState底层实现,复杂state,有依赖关系适合使用
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {number: state.number + 1};
case 'decrement':
return {number: state.number - 1};
default:
throw new Error();
}
}
function Counter(){
const [state, dispatch] = useReducer(reducer,{number:0});
return (
<>
Count: {state.number}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
)
}
lazy && Suspense
<Suspense fallback={<div>test</div>}>
路由组件
</Suspense>
路由懒加载
lazy(()=>import('url'))
react-router-dom
npm install react-router-dom@6 --save-dev
基本使用
import { Route, Routes } from "react-router-dom";
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/about" element={<About />}></Route>
</Routes>
</BrowserRouter>
嵌套路由
<Routes>
<Route path="user" element={<Users />}>
<Route path=":id" element={<UserDetail />} />
<Route path="create" element={<NewUser />} />
</Route>
</Routes>
import { useRoutes } from 'react-router-dom'
function App() {
const element = useRoutes([
{
path: '/',
element: <Layout />,
children: [
{
path: 'auth/*',
element: <Auth/>
},
{
path: 'basic/*',
element: <Basic/>
}
]
}
])
return (
{element}
)
}
访问 /user/123,渲染成
<Users>
<UserDetail/>
</Users>
访问/user/create,渲染成
<Users>
<NewUser/>
</Users>
重定向
<Route path="*" element={<Navigate to="/home" />} />
获取参数
params
Route path="/list/:id" component={List}
<Link to="/list/2" >跳转页面</Link>
this.props.history.push("/list/2");
//读取参数:this.props.match.params.id
let params = useParams();
search
<Route path='/web/departManange ' component={DepartManange}/>
<link to="web/departManange?tenantId=12121212">xxx</Link>
this.props.history.push({pathname:"/web/departManange?tenantId" + row.tenantId});
读取参数用: this.props.location.search
let [searchParams, setSearchParams] = useSearchParams();
state
<Route path='/sort ' component={Sort}/>
<Link to=>
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
//读取参数: this.props.location.query.state;
query
<Route path='/query' component={Query}/>
<Link to=>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name
编程式导航useNavigate
旧hooks useHistory
import { useHistory } from 'react-router-dom';
let history = useHistory();
history.push('/home','sada');
history.replace('/home',{test:'aaa'});
新hooks useNavigate
let navigate = useNavigate();
function handleClick() {
navigate("/manageData",{state:{value:111}});
navigate('/home', {replace: true});
}
<button onClick={() => navigate(-2)}>