1. create React App的使用
生成模板 npx create-react-app my-app --template typescript
1.1 定义一个组件
import React from "react";
const Robot = () => {
return <div></div>
}
export default Robot
import React from "react";
interface RobotProps {
name: string,
id: string,
email: string
}
const Robot : React.FC<RobotProps> = (props) => {
return <div></div>
}
export default Robot
1.2 css模块加载
需要定义.d.ts文件
declare module "*.css" {
const css: {[key:string]: string}
export default css
}
import React from 'react';
import styles from './App.module.css'
import robots from './mockdata/robots.json'
import Robot from "./components/Robot";
function App() {
return (
<div className={styles.app}>
<div className={styles.robotList}>
{
robots.map(r=> <Robot name={r.name} id={r.id} email={r.email} />)
}
</div>
</div>
);
}
npm install typescript-plugin-css-modules --save-dev
配置参数修改
tsconfig.json增加
"plugins": [
{
"name": "typescript-plugin-css-modules"
}
]
1.3 state与prop
直接修改state,组件不会触发renderi函数,页面不会渲染,正确的修改方式是使用setState0
1.4 state异步
<button
onClick={() => {
this.setState((preStatr, preProps) => {
return {count: preStatr.count +1}
}, () => {
console.log("count", this.state.count)
})
this.setState((preStatr, preProps) => {
return {count: preStatr.count +1}
}, () => {
console.log("count", this.state.count)
})
}}
>
Click
</button>
1.5 生命周期
- Mounting:创建虚拟DOM,渲染UI
- Updating:更新虚拟DOM,重新渲染UI
- Mounting:创建虚拟DOM,渲染UI
- Updating:更新虚拟DOM,重新渲染UI
- Unmounting:删除虚拟DOM,移除UI
// 在组件创建好dom元素以后、挂载进页面的时候调用
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => this.setState({ robotGallery: data }));
}
// * 生命周期第二阶段: 更新
// 在组件接收到一个新的 prop (更新后)时被调用。
// componentWillReceiveProps
// state getDerivedStateFromProps(nextProps, prevState){}
shouldComponentUpdate(nextProps, nextState){
return nextState.some !== this.state.some
}
// 组件更新后调用
componentDidUpdate(){}
// * 生命周期第三阶段: 销毁
// 组件销毁后调用,
// 可以当作析构函数 destructor 来使用
componentWillUnmount(){}
1.6 useState
const [count, setCount] = useState<number>(0);
<button
onClick={() => {
setCount(count + 1);
}}
>
Click
</button>
1.7 useEffect
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const responses = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
// .then(response => response.json())
// .then(data => setRobotGallery(data))
const data = await responses.json();
setRobotGallery(data);
} catch (e) {
// @ts-ignore
setError(e.message);
}
setLoading(false);
};
fetchData();
}, []);
1.8 useContent
const defaultContextValue = {
username: "阿莱克斯"
}
export const appContext = React.createContext(defaultContextValue)
<appContext.Provider value={defaultContextValue}>
<App />
</appContext.Provider>
消费端
import React, {useContext} from "react";
import styles from './Robot.module.css'
import { appContext } from "../index"
interface RobotProps {
name: string,
id: number,
email: string
}
const Robot : React.FC<RobotProps> = ({id, name,email}) => {
const value = useContext(appContext)
return <li>
<div className={styles.cardContainer}>
<img alt="robot" src={`https://robohash.org/${id}`} />
<h2>{name}</h2>
<p>{email}</p>
<p>作者: {value.username}</p>
</div>
</li>
}
export default Robot
1.8 高阶组件
返回一个组件的函数
1.9 react路由
npm install --save @types/react-router-dom
2 路由
2.1获取路由参数
<Route path="/detail/:touristRouteId" component={Detail}/>
import React from "react";
import { RouteComponentProps } from "react-router-dom";
interface MatchParams {
touristRouteId: string;
}
export const DetailPage: React.FC<RouteComponentProps<MatchParams>> = (
props
) => {
// console.log(props.history);
// console.log(props.location);
// console.log(props.match);
return <h1>路游路线详情页面, 路线ID: {props.match.params.touristRouteId}</h1>;
};
2.2跨组件路由
withRoute
link
useRoute
3. redux
npm install redux
3.1 流程
3.1.1 初始化store
store.ts
import {createStore} from 'redux'
import LanguageReduce from './languageReduce'
export const store = createStore(LanguageReduce)
export default store
languageState.ts
export interface LanguageState {
language: "en" | "zh";
languageList: { name: string; code: string }[];
}
const defaultState: LanguageState = {
language: "zh",
languageList: [
{ name: "中文", code: "zh" },
{ name: "English", code: "en" },
],
};
// 通过action去生成一个新的state
export default (state = defaultState, action: any) => {
if(action.type === 'changeLanguage') {
const newState = {...state, language: action.playload}
console.log(newState)
return newState
}
return state;
};
3.2 订阅store
constructor(props: any) {
super(props);
const storeState = store.getState();
this.state = {
language: storeState.language,
languageList: storeState.languageList,
};
store.subscribe(() => {
const storeState = store.getState()
this.setState({
language: storeState.language
})
})
}
<Dropdown.Button
style={{ marginLeft: 15 }}
overlay={
<Menu onClick={this.menuClickHandler}>
{this.state.languageList.map((l) => {
return <Menu.Item key={l.code}>{l.name}</Menu.Item>;
})}
</Menu>
}
icon={<GlobalOutlined />}
>
{this.state.language === "zh" ? "中文" : "English"}
</Dropdown.Button>
4. 国际化
4.1安装
npm install react-i18next i18next --save
4.2 初始化
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import translation_en from "./en.json";
import translation_zh from "./zh.json";
const resources = {
en: {
translation: translation_en,
},
zh: {
translation: translation_zh,
},
};
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
resources,
lng: "zh",
// keySeparator: false, // we do not use keys in form messages.welcome
// header.slogan
interpolation: {
escapeValue: false, // react already safes from xss
},
});
export default i18n;
4.3 页面引入
import {withTranslation, WithTranslation} from 'react-i18next'
export class HomeComponts extends React.Component<WithTranslation> {
render() {
console.log(this.props.t)
const {t} = this.props
return <div className={styles.App}>
<Header/>
<div className={styles["page-content"]}>
<Row style={{ marginTop:20}}>
<Col span={6}>
<SideMenu/>
</Col>
<Col span={18}>
<Carouseld/>
</Col>
</Row>
<ProductCollection title={
<Typography.Title>
{t("home_page.hot_recommended")}
</Typography.Title>
} leftImage={sideImage} products={productList1} />
<BusinessParters/>
</div>
<Footer/>
</div>
}
}
export const Home = withTranslation()(HomeComponts)
5.action工厂模式
action工厂模式
- 新增 languageActions.ts
export const CHANGE_LANGUAGE = "changeLanguage"
interface ChangeLanguageAction {
type: typeof CHANGE_LANGUAGE,
playload: "zh" | "en"
}
export type LanguageActionTypes = ChangeLanguageAction
export const changeLanguageActionCreator = (laguageCode: "zh" | "en") : ChangeLanguageAction => {
return {
type: CHANGE_LANGUAGE,
playload: laguageCode
}
}
- reduce判断
switch (action.type) {
case CHANGE_LANGUAGE:
i18n.changeLanguage(action.playload)
return {...state, language: action.playload}
}
return state;
- 引用import
import {changeLanguageActionCreator} from '../../redux/language/languageActions';
menuClickHandler = (e: any) => {
console.log(e)
const action = changeLanguageActionCreator(e.key)
store.dispatch(action)
}
6.react-redux
npm install react-redux
npm install @types/react-redux --save--dev
6.1 typescript 连接react与react-redux
6.2 类组件方式
- index.js 引入, Provider包裹
import {Provider} from "react-redux";
import store from './redux/store'
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
- 在相关组件引入connet
import {connect} from 'react-redux'
- 构建流出属性 mapToStateProps
const mapToStateProps = (state: rootState) => {
return {
language: state.language,
languageList: state.languageList
}
}
- 通过action构建流入
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
changeLanguage: (code: "zh" | "en") => {
const action = changeLanguageActionCreator(code)
dispatch(action)
}
}
}
- 返回包装
export const Header = connect(mapToStateProps,mapDispatchToProps)(withTranslation()(withRouter(HeaderComponts)))
1
2
TypeScript
- 调用prop属性
menuClickHandler = (e: any) => {
console.log(e)
this.props.changeLanguage(e.key)
}
6.3 函数组件方式
- index.js 引入, Provider包裹
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
import {useSelector} from "../../redux/hooks"
import {useDispatch} from "react-redux"
- 调用
const menuClickHandler = (e: any) => {
console.log(e)
dispatch(changeLanguageActionCreator(e.key))
}
6.4 定义一个模块开发流程
- 定义reduce
recommendProductsReduce.ts
import {
recommendProductAction,
RECOMMONEND_PRODUCTS_FAIL,
RECOMMONEND_PRODUCTS_START,
RECOMMONEND_PRODUCTS_SUCCESS
} from './recommendProductsActions'
interface RecommendProductState {
productList: any[],
loading: boolean,
error: string | null
}
const defaultState: RecommendProductState = {
productList: [],
loading: true,
error: null
}
export default (state = defaultState, action: recommendProductAction) => {
switch (action.type) {
case RECOMMONEND_PRODUCTS_START:
return {...state, loading: true}
case RECOMMONEND_PRODUCTS_SUCCESS:
return {...state, loading: false, productList: action.payload}
case RECOMMONEND_PRODUCTS_FAIL:
return {...state, loading: false, error: action.payload}
default:
return state
}
}
- 定义action
export const RECOMMONEND_PRODUCTS_START = "recommonend_products_start" //正在调用推荐信息
export const RECOMMONEND_PRODUCTS_SUCCESS = "recommonend_products_success" //调用推荐信息成功
export const RECOMMONEND_PRODUCTS_FAIL = "recommonend_products_end" //调用推荐信息失败
interface FetchRecommendProductStart {
type : typeof RECOMMONEND_PRODUCTS_START
}
interface FetchRecommendProductSuccess {
type : typeof RECOMMONEND_PRODUCTS_SUCCESS,
payload: any
}
interface FetchRecommendProductFail {
type : typeof RECOMMONEND_PRODUCTS_FAIL,
payload: any
}
export type recommendProductAction = FetchRecommendProductStart
| FetchRecommendProductSuccess
| FetchRecommendProductFail
export const fetchRecommendProductStartCreator = () : FetchRecommendProductStart => {
return {
type : RECOMMONEND_PRODUCTS_START
}
}
export const fetchRecommendProductSuccessCreator = (data: any) : FetchRecommendProductSuccess => {
return {
type : RECOMMONEND_PRODUCTS_SUCCESS,
payload: data
}
}
export const fetchRecommendProductFailCreator = (error: any) : FetchRecommendProductFail => {
return {
type : RECOMMONEND_PRODUCTS_FAIL,
payload: error
}
}
- 类组件connect连接
import {connect} from 'react-redux'
- 定义mapStateToProps
const mapStateToProps = (state: rootState) => {
return {
loading: state.recommendProducts.loading,
productList: state.recommendProducts.productList,
error: state.recommendProducts.error
}
}
- 定义mapDispatchToProps
import {Dispatch} from 'redux'
import {fetchRecommendProductStartCreator, fetchRecommendProductSuccessCreator, fetchRecommendProductFailCreator} from "../../redux/recommendProducts/recommendProductsActions"
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
fetchStart: () => {
dispatch(fetchRecommendProductStartCreator())
},
featchSuccess: (data: any) => {
dispatch(fetchRecommendProductSuccessCreator(data))
},
featchFail: (error: any) => {
dispatch(fetchRecommendProductFailCreator(error))
},
};
};
- connect连接
export const Home = connect(mapStateToProps, mapDispatchToProps)(withTranslation()(HomeComponts))
- 请求调用
async componentDidMount() {
this.props.fetchStart()
try {
const { data } = await axios.get("http://123.56.149.216:8080/api/productCollections",{
headers : {
"x-1c0de":"FB80558A73FA658E"
}
})
this.props.featchSuccess(data)
}catch (error: any) {
this.props.featchFail(error.message)
}
}
7.远程请求
npm install axios
8.redux中间件
可以使用在store里处理副作用,多个组件可以共享使用
8.1案例
- 引入thunk, applyMiddleware
import {createStore, combineReducers,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
export const store = createStore(rootReducer, applyMiddleware(thunk))
- 定义action构造方法
export const giveMeDataActionCreator = ():
ThunkAction<void, rootState, unknown, recommendProductAction> =>
async (dispatch, getState) => {
try {
dispatch(fetchRecommendProductStartCreator())
const { data } = await axios.get("http://123.56.149.216:8080/api/productCollections",{
headers : {
"x-1c0de":"FB80558A73FA658E"
}
})
fetchRecommendProductSuccessCreator(data)
}catch (error) {
dispatch(fetchRecommendProductFailCreator(error.message))
}
}
- 使用action
import {giveMeDataActionCreator} from "../../redux/recommendProducts/recommendProductsActions"
const mapDispatchToProps = (dispatch: any) => {
return {
giveMeData: () => {
dispatch(giveMeDataActionCreator())
}
};
};
componentDidMount() {
this.props.giveMeData()
}
8.2自定义中间件
公式: const middleware (store)=>(next)=>(action)=>{}
actionLog.ts
import {Middleware} from 'redux'
export const actionLog: Middleware = (store)=>(next)=>(action)=>{
console.log("当前state" + JSON.stringify(store.getState()))
console.log("action" + JSON.stringify(action))
next(action)
console.log("state更新" + JSON.stringify(store.getState()))
}
引入
import {actionLog} from './middlewares/actionLog'
export const store = createStore(rootReducer, applyMiddleware(thunk, actionLog))
9.redux-toolkit
npm install @reduxjs/toolkit
9.1 使用方法一,自己处理回调
- 构建slice
import {createSlice, PayloadAction} from "@reduxjs/toolkit"
interface ShopDetail {
loading: boolean,
data: any,
error: string | null
}
const initialState: ShopDetail = {
loading: false,
data: null,
error: null
}
export const ShopDetailSlice = createSlice({
name : "shopDetail",
initialState,
reducers: {
featchStart: (state) => {
state.loading = true
},
featchSuccess: (state, action) => {
state.loading = false
state.data = action.payload
},
featchFail: (state, action: PayloadAction<string | null>) => {
state.loading = false
state.error = action.payload
}
}
})
- 定义configureStore
export const store = configureStore({
reducer: rootReducer,
middleware: getDefaultMiddleware => [...getDefaultMiddleware(), actionLog],
devTools: true
})
- 调用接口
useEffect(() => {
dispatch(ShopDetailSlice.actions.featchStart);
// 获取产品数据
const featchDate = async () => {
try {
const resp = await axios.get(`http://localhost:8199/api/shop/queryById/${touristRouteId}`, {
headers : {
"Authorization":"111"
}
});
dispatch(ShopDetailSlice.actions.featchSuccess(resp.data.data.pmsShop))
} catch (error) {
dispatch(ShopDetailSlice.actions.featchFail(error))
}
}
featchDate();
},[])
9.2 使用方法二,自动处理回调结果
- 构建slice
import {createSlice, PayloadAction, createAsyncThunk} from "@reduxjs/toolkit"
import axios from "axios";
interface ShopDetail {
loading: boolean,
data: any,
error: string | null
}
const initialState: ShopDetail = {
loading: false,
data: null,
error: null
}
export const getShopDetail = createAsyncThunk("shop/shopDetail",
async (touristRouteId:string, ThunkApi) => {
const resp = await axios.get(`http://localhost:8199/api/shop/queryById/${touristRouteId}`, {
headers : {
"Authorization":"111"
}
});
return resp.data.data.pmsShop;
})
export const ShopDetailSlice = createSlice({
name : "shopDetail",
initialState,
reducers: {
},
extraReducers: {
[getShopDetail.pending.type]: (state) => {
state.loading = true
},
[getShopDetail.fulfilled.type]: (state, action) => {
state.loading = false
state.data = action.payload
},
[getShopDetail.rejected.type]: (state, action: PayloadAction<string | null>) => {
state.loading = false
state.error = action.payload
}
}
})
- 定义configStore
export const store = configureStore({
reducer: rootReducer,
middleware: getDefaultMiddleware => [...getDefaultMiddleware(), actionLog],
devTools: true
})
- 调用接口
import {getShopDetail} from "../../redux/shopDetail/slice"
useEffect(() => {
dispatch(getShopDetail(touristRouteId));
},[])