配置文件详细介绍,最新版本
前期准备
在开始创建项目前,确认是否安装了node.js运行环境,打开电脑终端输入node -v即可,若没有版本号。大家可自行下载。这里开始“简单”记录一下react通过脚手架创建项目的过程。
npm install -g create-react-app 全局安装create-react-app
npm uninstall -g create-react-app 卸载
create-react-app -V 检测React版本号
React项目创建
- 打开终端,输入命令:npx create-react-app react-project-demo --template typescript
- 等待项目创建完成,然后输入命令:cd react-project-demo
- 输入命令:npm start
- 打开浏览器,输入地址:http://localhost:3000/
npx create-react-app react-project-demo --template typescript
npm init vite@latest react-project-demo --template typescript
cd react-project-demo
npm start
安装路由
- 输入命令:npm install react-router-dom --save 默认安装的式router6.x。
- 简单使用
import { HashRouter, Routes, Route } from "react-router-dom";
ReactDOM.render(
<HashRouter>
<Routes>
<Route path="/home" element={<Home />}></Route>
<Route path="/" element={<Login />}></Route>
</Routes>
</HashRouter>,
document.getElementById("root")
);
- 配置路由
//routers.tsx
const staticRoute = [
{
path: '/',
element: <Home />,
children: [
{
path: 'about',
element: <div>About</div>
},
{
path: 'contact',
element: <div>Contact</div>
}
]
},
{
path: '/login',
element: <Login />,
}
]
export default staticRoute;
//index.tsx
root.render(
// <React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
// </React.StrictMode>
);
//App.tsx
function App() {
const elements = useRoutes(staticRoute);
return (
<div className="App">
<div>
<NavLink to="/">Home</NavLink> |
<NavLink to="/login">login</NavLink> |
</div>
<div>
{elements}
</div>
</div>
);
}
//Home.tsx 配置子路由
import { Outlet } from "react-router-dom";
function Home() {
return (
<div>
<h1>Home</h1>
<div>
<Outlet />
</div>
</div>
);
}
export default Home;
react hook
- useState
// Hook.tsx 界面
//useState 状态
const [people, setPeople] = useState<{ name: string, age: number }>({ name: "张三", age: 1 })
//方法
const handleUpdate = () => {
setPeople({ ...people, name: '王五' });
}
//使用
<h1>{people.name}</h1>
<button onClick={handleUpdate}> change name </button>
- useRef
const inputEl = useRef<HTMLInputElement>(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
//界面
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
// wrong! 注意:无法直接通过ref来引用函数组件,因为函数组件没有对象
// <FunctionComponent ref={ref}></FunctionComponent>
- useEffect
useEffect(() => {
console.log("useEffect--当people改变时");
}, [people]);
useEffect(() => {
console.log("useEffect--弟一次加载时");
}, []);
useEffect(() => {
console.log("useEffect--界面更新时");
});
useEffect(() => {
//这边返回的清除函数的执行时机:
//是在下一次函数组件re-render之后,useEffect之前执行
console.log("useEffect--清除函数执行了");
return () => {
console.log("清除函数执行了");
}
}, []);
- 缓存变量 useMemo
useMemo类似于Vue的计算属性,如果有一些属性值是可以根据其他值推导出来的,我们就可以使用useMemo
它的参数有两个:
一个函数,函数的返回值就是useMemo的结果
数组依赖项,表示触发第一个函数参数的条件
const [count, setCount] = useState(100);
//useMemo()可以实现类似于Vue中的计算属性的功能,还可以用来缓存数据
const obj = {
name: "zhangsan",
};
//下面的obj2在函数组件每一次重新渲染的时候都是同一个对象,没有重新初始化
const obj2 = useMemo(() => {
return {
name: "zhangsan",
};
}, []);
//jsx////////////////
<button onClick={() => setCount(count + 1)}>点我修改count</button>
{
// 点击按钮以后,由于函数会重新执行,父组件中将创建一个新的obj,传递给子组件的obj也会改变
// 因此会触发子组件的自动更新
}
<Son obj={obj}></Son>
{
// 不会触发更新
}
<Son obj={obj2}></Son>
- memo
- memo() 是一个高阶组件,高阶组件其实就是一个函数,只不过这个函数的参数是一个组件,函数的返回值是一个新的组件
- 只要父亲传递给孩子的props发生了变化就应该刷新子组件(如果父亲没有给子组件传递props或者父亲给子组件传递的props没有改变,则子组件不应该刷新
- 父组件如果使用了useMemo,子组件一定要配套使用memo函数
function Son(props: IProps){
console.log("Son render");
return (
<div>
Son
</div>
);
};
export default memo(Son);
- 缓存函数 useCallback
const [text,setText] = useState("")
const changeHandler = useCallback((event:React.ChangeEvent<HTMLInputElement>)=>{
setText(event.target.value)
},[])
//界面
<InputSun onChange={changeHandler}></InputSun>
- useContext
跨级组件通信,实现同一子树下所有节点可统一共享子树根节点的数据
//src/context/index.ts
type ContextType = {
name: string,
age: number
}
let context: Context<ContextType | null> = createContext<ContextType | null>(null)
// 暴露出来一个 context 对象
export default context;
//父组件////////////////////
<div>
<Context.Provider
value={{name: "黑猫几绛", age: 100}}
>
<ContextSon></ContextSon>
</Context.Provider>
</div>
// 子组件 ////////////////////////
function ContextSon() {
// 在子组件中获取根组件暴露的数据
const contextValue = useContext(Context);
return (
<div>
<div>text文本为:{contextValue?.name}</div>
</div>
)
}
- useReducer
useReducer是在函数组件中实现类似 Redux 功能的一个Hook。他接收两个参数,第一个参数是一个recuder(纯函数),第二个参数是state的初始值。
他返回一个状态 state和 dispath,state是返回状态中的值,而 dispatch 是一个可以发布事件来更新 state 的。
const reducer = (state: StateType, action: any) => {
switch (action.type) {
case "ADD":
return { count: state.count + 1 };
case "SUB":
return { count: state.count - 1 };
default:
return state;
}
};
// 使用useReducer(纯函数) ,得到state和dispatch
const [state, dispatch] = useReducer(reducer, { count: 1000 });
// jsx ////////////
<div>
{state.count}
<button onClick={() => dispatch({ type: "ADD" })}>点我+1</button>
<button onClick={() => dispatch({ type: "SUB" })}>点我-1</button>
</div>
- useReduce & useContext 实现全局数据共享
useContext负责向子孙组件暴露数据
useReducer提供全局的state、reducers、dispatch等
- 自定义 Hooks
import React, { useState, useCallback, useEffect } from "react";
export const useWinSize = () => {
// 1. 使用useState初始化窗口大小state
const [size, setSize] = useState({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
});
const changeSize = useCallback(() => {
// useCallback 将函数缓存起来 节流
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
});
}, []);
// 2. 使用useEffect在组件创建时监听resize事件,resize时重新设置state (使用useCallback节流)
useEffect(() => {
//绑定一次页面监听事件 组件销毁时解绑
window.addEventListener("resize", changeSize);
return () => {
window.removeEventListener("resize", changeSize);
};
}, []);
return size;
};
redux
- 安装依赖
npm install redux react-redux redux-thunk --save
npm install @types/react-redux --save-dev
// redux 与 redux-thunk有问题,所有降级了。20240123
npm install redux@4.2.1 --save
- redux 核心代码
//redux/store.js
import { legacy_createStore as createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
import {thunk} from 'redux-thunk';
export default createStore(
rootReducer,
applyMiddleware(thunk)
);
//redux/index.js
import { combineReducers } from 'redux';
import dictionary from './dictionary';
const rootReducer = combineReducers({
dictionary
});
export default rootReducer;
//redux/dictionary.js
import { SECURITY_LEVEL, METADATA_TYPE, DATA_TYPE, VALUE_TYPE } from '../types/dictionary';
const init_state = {
levelType: [], //安全级别
metaType: [], //元数据类型
dataType: [], //来源类型-类型
valueType: [] //取值范围类型
};
export default function dictionary(state = init_state, action:any) {
const { type, data } = action;
switch (type) {
case SECURITY_LEVEL:
return Object.assign({}, state, { levelType: data });
case METADATA_TYPE:
return Object.assign({}, state, { metaType: data });
case DATA_TYPE:
return Object.assign({}, state, { dataType: data });
case VALUE_TYPE:
return Object.assign({}, state, { valueType: data });
default:
return state;
}
}
//redux/types/dictionary.js
export const INIT_LANG = 'INIT_LANG'; //示例
export const SECURITY_LEVEL = 'SECURITY_LEVEL';
export const METADATA_TYPE = 'METADATA_TYPE';
export const DATA_TYPE = 'DATA_TYPE';
export const VALUE_TYPE = 'VALUE_TYPE';
- 入口文件引入
import store from './redux/store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
- 组件中使用
import { initRoutes,getSecurityLevelList } from '../redux/actions/dictionary';
import { useSelector, useDispatch } from 'react-redux';
function Redux() {
const dispatch = useDispatch();
const levelType = useSelector((state:any) => state.dictionary.levelType); // 示例
const metaType = useSelector((state:any) => state.dictionary.metaType); //
useEffect(() => {
initDict();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const initDict = () => {
dispatch(initRoutes(['aaa']));
};
const onButtonClick = () => {
dispatch(initRoutes(['leolee']));
};
const onButtonClick2 = () => {
dispatch(getSecurityLevelList());
};
return (
<>
<div>redux</div>
<div>{levelType[0]}</div>
<div>{metaType}</div>
<button onClick={onButtonClick}>修改Redux</button>
<button onClick={onButtonClick2}>修改Redux2</button>
</>
);
}