# react-travel
**Repository Path**: bing-cola/react-travel
## Basic Information
- **Project Name**: react-travel
- **Description**: react17+ts 旅游网
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-10-14
- **Last Updated**: 2022-04-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# React
## 初始化项目
1. `npx create-react-app react-travel --template typescript`
2. `cd react-travel`
3. `npm run start`
---
## CSS 模块化 - CSS in JS
### typescript css
1. 安装插件:yarn add typescript-plugin-css-modules --save-dev
2. tsconfig.json中配置插件:`"compilerOptions":{ "plugins": [ { "name": "typescript-plugin-css-modules" } ] }`
3. vscode配置:创建`.vscode/settings.json` :
```json
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
```
### css需要作为模块被引入组件
1. 将App.css重命名为:App.module.css
```css
/* App.module.css */
.center {
text-align: center;
}
.list {
line-height: 30px;
font-size: 20px;
}
```
2. 定义声明文件custom.d.ts:
对css引用对象的支持,否则.tsx会报错
```js
// custom.d.ts
declare module '*.css' {
const css: { [key: string]: sting };
export default css;
}
```
3. 组件中使用:
```html
// App.tsx
import styles from './App.module.css';
function App() {
return (
);
}
export default App;
```
---
## 使用 Ant Design
官网:https://ant.design/index-cn
1. 安装UI组件库:`yarn add antd`
2. 安装Icon图标:`yarn add @ant-design/icons --save`
3. 在`index.tsx`中引入css:`import 'antd/dist/antd.css';`
4. 组件中使用UI:
```html
import { Input } from 'antd';
```
5. 组件中使用Icon:
```html
import { MessageOutlined } from '@ant-design/icons';
;
```
---
## 路由
### 安装路由
1. 安装:`yarn add react-router-dom --save-dev`
2. 会自动安装`react-router`核心框架
3. 安装typescript的声明文件:`npm install @types/react-router-dom --save-dev`
### 使用路由
1. BrowserRouter:路由导航与原生浏览器操作行为一致
2. Route:路由的路径解析原理与原生浏览器一致,可以自动识别url路径
3. Switch:路径的切换以页面为单位,不要页面堆叠
基础路由eg:
```js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import { Home } from './pages'
function App() {
return (
{/* Switch 解决页面叠加问题,每次只渲染一个路由页面 */}
登录页面
)} />
404 not found 页面
)} />
);
}
export default App;
```
### 路由中参数传递
使用分段路由Segments:`http://localhost:3000/products/11121314`
#### 1. `App.tsx`中添加详情页的路由
```js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import { Home, Detail } from './pages'
function App() {
return (
{/* 路由添加参数id */}
);
}
export default App;
```
#### 2. `Home.tsx`中跳转到详情页的路由
1. 使用高阶函数:
```js
import React from "react";
import { withRouter } from "react-router-dom"; // 高阶函数
const HomeComponent: React.FC = ({ history, location, match }) => {
console.log(history, location, match);
return (
history.push(`detail/123456`)}>
跳转至详情页,并传递参数id
);
}
export const Home = withRouter(HomeComponent); // 使用高阶函数封装路由
```
2. 使用hook:
```js
import React from 'react';
import { useHistory, useLocation, useParams, useRouteMatch } from 'react-router-dom'; // hook
export const Home: React.FC = () => {
// 使用hook
const history = useHistory();
const location = useLocation();
const params = useParams();
const match = useRouteMatch();
return (
history.push(`detail/123456`)}>
跳转至详情页,并传递参数id
);
};
```
3. 使用Link:
```js
import React from "react";
import { Link } from "react-router-dom"; // link
export const Home: React.FC = () => {
return (
跳转至详情页,并传递参数id
);
}
```
#### 3. `Detail.tsx`详情页中获取参数
```js
import React from 'react';
export const Detail: React.FC = (props) => {
console.log(props.match.params.id);
}
```
---
## 国际化(I18n)
### 安装
`npm install react-i18next i18next --save`
或
`yarn add react-i18next i18next --save`
### 配置
新建文件夹`i18n\config.ts`:
```js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import translation_en from './en.json'; // 配置的英文json
import translation_zh from './zh.json'; // 配置的中文json
const resources = {
en: {
translation: translation_en,
},
zh: {
translation: translation_zh,
},
};
i18n.use(initReactI18next).init({
resources,
lng: 'zh',
interpolation: {
escapeValue: false,
},
});
export default i18n;
```
### 使用
1. `index.tsx`中引入:`import './i18n/config'`
2. 组件中`Home.tsx`:
```js
import React from 'react';
import { useTranslation } from 'react-i18next'
export const Home: React.FC = () => {
const { t } = useTranslation()
return (
{t('home.detail')}
);
};
```
3. 点击按钮切换,`reducer.ts`中:
```js
import i18n from 'i18next';
export interface languageState {
language: 'zh' | 'en';
languageList: { name: string; code: string }[];
}
const defaultState: languageState = {
language: 'zh',
languageList: [
{ name: '中文', code: 'zh' },
{ name: 'English', code: 'en' },
],
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'change_language':
i18n.changeLanguage(action.value);
return { ...state, language: action.value };
default:
return state;
}
};
export default reducer;
```
React的核心思想就是组件化,组件化带来最大好处就是组件彼此独立,可以复用。
## 什么是钩子(hooks)
1. 消息处理的一种方法,用来监视指定程序
2. 函数组件中需要处理副作用,可以用钩子把外部代码“钩”进来
3. 常用钩子:`useState`,`useEffect`,`useContext`,`useReducer`
4. hooks一律使用`use`前缀命名:`useXxx`
## 副作用
纯函数:给一个函数同样的参数,那么这个函数永远返回同样的值。
副作用与穿函数相反,指一个函数处理了与返回值无关的事情。
输入参数一样,而输出结果不确定的情况就是副作用。
纯函数中没有副作用,有副作用的不是纯函数。
React中的副作用有:state状态的改变、生命周期、构建函数...
函数式组件中使用`useEffect`处理副作用
1. 当`useEffect`的第二个参数为一个非空数组时,会在`count`值发生变化时调用(相当于vue中的`watch`)
```js
useEffect(() => {
document.title = `You clicked ${count} times`; // 监听count值变化
}, [count])
```
2. 当`useEffect`的第二个参数为一个空数组时,初始化调用一次之后不再执行(相当于`componentDidMount`)
```js
useEffect(() => {
console.log('hello world'); // 仅在初始化时调用一次
}, [])
// 等价于
componentDidMount() {
console.log('hello world');
}
```
3. 当`useEffect`没有第二个参数时,组件的初始化和更新都会执行,(相当于`componentDidMount` + `componentDidUpdate`),容易死循环(夺命连环call)
```js
useEffect(() => {
document.title = `You clicked ${count} times`;
});
// 等价于
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
```
4. 当`useEffect`返回一个函数时,这个函数会在组件卸载时执行(相当于`componentDidMount`+`componentWillUnmount`)
```js
useEffect(() => {
const id = setInterval(() => {
setCount(c => c + 1);
}, 1000);
return () => clearInterval(id); // 相当于componentWillUnmount
}, []);
// 等价于
componentDidMount() {
this.id = setInterval(() => {
this.setState({count: this.state.count + 1})
}, 1000);
}
componentWillUnmount() {
clearInterval(this.id);
}
```
---
## 高阶组件(HOC)
1. 高阶组件(HOC)就是一个返回了组件的函数
2. 通过组件嵌套的方法给子组件添加更多的功能
3. 接收一个组件作为参数并返回一个经过改造的新组件
简而言之,高阶组件是参数为组件,返回值为新组件的函数。
`const hoc = higherOrde(wrappedComponent)`
组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。
### 高阶组件优点
1. 抽取重复代码,实现组件复用
2. 条件渲染,控制组件的渲染逻辑(渲染劫持)
3. 捕获/劫持被处理组件的生命周期
```js
import React from 'react';
const withAddToCart = (ChildComponent)=>{
return (props) =>{
return
}
}
```
## React-Redux
https://react-redux.js.org/
### 1.安装
npm install react-redux @types/react-redux
yarn add react-redux @types/react-redux
### 2.引入Provider
在`index.tsx`中引入Provider:
```js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'; // 引入Provider
import store from './redux/store'; // 引入store
ReactDOM.render(
{/* 使用Provider并加载数据仓库 */}
,
document.getElementById('root')
);
```
### 3.connect()
组件中使用connect().
```js
import { connect } from 'react-redux';
// ...
export const Xxx = connect(mapStateToProps, mapDispatchToProps)(XxxComponents);
```