- 跨域
最简单的方式:package.json中配置节点
"proxy": "http://localhost:9004"
axios直接请求前端服务器端口形式3000,代理会调9004的端口
多台服务器:src目录下创建setupProxy.js文件 文件名不允许修改
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
//遇见api1前缀的请求,就会触发该配置
proxy('/api1', {
target: 'http://localhost:9004', //请求转发给谁
changeOrigin: true, //控制服务器收到的响应头中Host字段的值
pathRewrite: { '^/api1': '' } //重写请求路径
}),
//遇见api2前缀的请求,就会触发该配置
proxy('/api2', {
target: 'http://localhost:9005', //请求转发给谁
changeOrigin: true, //控制服务器收到的响应头中Host字段的值
pathRewrite: { '^/api2': '' } //重写请求路径
})
);
};
请求方法
getStudentData = () => {
axios.get('/ADMIN/auth/system/kaptcha').then(
response => {
console.log('成功了', response.data);
},
error => {
console.error('失败了', error);
}
);
};
fetch请求
//fetch请求
appFetch = async()=> {
try {
const response = await fetch('/admin/test/?id=1')
const data = await response.json()
console.log(data)
} catch (error) {
console.log('请求出错',error)
}
}
十、向路由组件传递参数
1.params参数传递
##路由链接携带params参数
<Link to={`/demo/test/${params.id}/${params.title}`}>详情</Link>
##注册路由 params参数声明接收
<Route path="/demo/test/:id/:title" component={Home} />
##接收params参数
const {id,title} = this.props.match.params
2.search参数传递
##声明引入对象 search参数为?id=1&title=测试
import qs from 'queryString'
------------------------------
##例子
let obj = {id:1,title:test}
consol.log(qs.stringify(obj))
结果:id=1&title=test
------------------------------
let str = 'id=1&title=test'
consol.log(qs.parse(str))
结果:{id:1,title:test}
-----------------------------
##路由链接携带search参数
<Link to={`/demo/test?${params.id}&{params.title}`}>详情</Link>
##注册路由 无需声明接收
<Route path="/demo/test" component={Home} />
##接收参数
const {search} = this.props.location
const params = search.slice(1)
结果:{id:1,title:test}
------------------------------
3.state参数传递
##路由链接携带state参数
<Link to={{pathname:'/demo/test',state={id:1,title:'test'}}}>详情</Link>
##注册路由 无需声明接收
<Route path="/demo/test" component={Home} />
##接收参数
const {state} = this.props.location
结果:{id:1,title:test}
------------------------------
十一、react中replace()和push()的模式区别
replace跳转不会形成history,不可返回到上一层,无痕浏览
<NavLink replce to='/demo/test'/>
默认为push模式,push跳转会形成history,可返回到上一层
------------------
编程式路由导航
this.props.history.replace(‘router地址’)
this.props.history.push(‘router地址’)
this.props.history.goBack(‘router地址’)
this.props.history.goFaward(‘router地址’)
this.props.history.goFaward('传数字前进后退')
十二、withRouter的使用
正常情况下一般组件是没有路由组件的api,如果一般组件需要借助路由组件的API方法进行传递参数,需要借助withRouter
import {withRouter} from 'react-router-dom'
/*
这儿是组件,比如组件名称为Test
*/
export default withRouter(Test)
十三、BrowserRouter和HashRouter路由的区别
1.底层原理不一样
BrowserRouter使用的是H5的History API,不兼容IE9以下版本。
HashRouter使用的是URL的哈希值
2.path表现形式不一样
BrowserRouter的路径当中没有#,例如:localhost:3000/demo/test
HashRouter的路径当中包含#,例如:localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
BrowserRouter没有任何影响,因为state保存在history对象当中
HashRouter刷新后悔导致路由state的参数缺失
4.备注:HashRouter可以用于解决一些路径错误相关的问题
十四、React UI组件库
material-ui(国外)
官网:https://material-ui.com/zh/
ant-design(国内蚂蚁金服)
官网:https://ant.design/index-cn
安装:yarn add antd
十五、redux精简版
(1)去除Cout组件下自身的状态
import React, { Component } from 'react';
import { Divider } from 'antd';
//引入store
import store from '../../redux/store';
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
store.dispatch({ type: 'increment', data: value * 1 });
};
//相减
decrement = () => {
const { value } = this.selectNumber;
store.dispatch({ type: 'decrement', data: value * 1 });
};
//奇数相加
incrementIfOdd = () => {
const { value } = this.selectNumber;
const count = store.getState();
if (count % 2 === 0) return;
store.dispatch({ type: 'increment', data: value * 1 });
};
//异步相加
incrementAsync = () => {
const { value } = this.selectNumber;
setTimeout(() => {
store.dispatch({ type: 'increment', data: value * 1 });
}, 1000);
};
render() {
return (
<div>
<h2>当前求和值是:{store.getState()}</h2>
<Divider />
<select
ref={c => {
this.selectNumber = c;
}}
>
<option value="0">--请选择--</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和奇数相加</button>
<button onClick={this.incrementAsync}>异步相加</button>
</div>
);
}
}
(2)src目录下简历文件夹redux,再建立store.js,和reducer相应的js。如store.js
/*
整个应用只有一个store
*/
//引入createStore 创建核心的store对象
import { createStore } from 'redux';
//引入为Count组件服务的reducer
import countReducer from './count_reducer';
export default createStore(countReducer);
count_reduce.js
/*
1.该文件适用于创建一个Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,第一个参数为之前的状态,第二个为动作对象
*/
import { INCREMENT, DECREMENT } from './constant';
const initState = 5; //初始化状态
export default function countReducer(preState = initState, action) {
//从action对象当中获取type,data
const { type, data } = action;
//根据type如何加工数据
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
在入口文件index.js里面全局订阅监测
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './redux/store';
ReactDOM.render(<App />, document.getElementById('root'));
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById('root'));
});
count_action.js
/*
该文件专门为Count组件生成Action对象
*/
import { INCREMENT, DECREMENT } from './constant';
// function createIncrementAction(data) {
// return { type: 'increment', data };
// }
// function createDecrementAction(data) {
// return { type: 'decrement', data };
// }
//同步action
export const crtIncrementAction = data => ({ type: INCREMENT, data });
export const crtDecrementAction = data => ({ type: DECREMENT, data });
//异步action 一般里面都会调用同步action 不必要使用
export const crtDecrementAsncAction = (data, time) => {
return dispatch => {
setTimeout(() => {
dispatch(crtIncrementAction(data));
}, 500);
};
};
constant.js
/*
该模块是定义action的常量
*/
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
注:
1.BrowserRouter以‘/’匹配,index.html当中如果引入css样式,采用绝对路径的写法,HashRouter以‘#’匹配,#后面的资源默认为前端资源,不会向后台服务器发起请求