获取Dom
import React, { Component } from 'react';
export default class Example extends Component {
state = {
dimensions: null,
};
componentDidMount() {
this.setState({
dimensions: {
width: this.container.offsetWidth,
height: this.container.offsetHeight,
},
});
}
renderContent() {
const { dimensions } = this.state;
return (
<div>
width: {dimensions.width}
<br />
height: {dimensions.height}
</div>
);
}
render() {
const { dimensions } = this.state;
return (
<div className="Hello" ref={el => (this.container = el)}>
{dimensions && this.renderContent()}
</div>
);
}
}
线上部署刷新404
这个和vue是一样的问题,需要再nginx加入配置
location /{
try_files $uri $uri/ /index.html;
}
Error: EBUSY: resource busy or locked, lstat 'C:\hiberfil.sys'
今天遇到一个奇怪的报错,这个时候需要清空一下npm 缓存
方法一:删除 node_modules,然后再安装(npm i);
方法二:删除 node_modules,运行 npm cache clean 或者 npm cache clean --force 命令, 然后安装;
方法三:升级一下node版本,删除node_modules,然后再安装。
react 配置 stylus
1. 创建react项目
create-react-app react-demo
cd react-demo
2. 暴露config配置文件
先commit代码,如果不提交,执行以下指令执行会报错
npm run eject
3. 下载stylus相关包
npm install stylus stylus-loader --save-dev
4. 在config/webpack.config.js文件中配置
找到sass和css的配置
在原先的sass和css部分下面添加stylus配置
const stylusRegex =/\.styl$/;
const stylusModuleRegex=/\.module\.styl$/;
在 config/webpack.config.js 文件里
{ // 配置 stylus
test: stylusRegex,
exclude: stylusModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true, // 设置模块化
},
'stylus-loader'
),
sideEffects: true,
},
{
test: stylusModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
},
'stylus-loader'
),
},
4. 参考资料
react配置装饰器
1.安装:
npm install @babel/plugin-proposal-decorators --save-dev
2. package.json配置:
"babel": {
"presets": [
"react-app"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
3. 参考资料
装饰器connect问题:Error: The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose val...
react 使用props报错
报错:
is missing in props validation react/prop-types
1. 安装prop-types
npm i prop-types -S
2. 在页面中使用
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
setDate在componentDidMount周期报错
问题如下
Do not use setState in componentDidMount react/no-did-mount-set-state
官网回答
解决
第一步,但是会提示componentDidMount有问题
async componentDidMount () {
const { default: component } = await importComponent();
this.setState({
component: component
});
}
第二部,在周期内部通过async 同步处理
componentDidMount () {
(async () => {
const { default: component } = await importComponent();
this.setState({
component: component
});
})()
}
使用 antd 组件报错Please update the following components
在index.js中注释调严格模式
报错就没有了
神坑,setdata函数不能保证是同步的
官方说明
给 setState 传递一个对象与传递一个函数的区别是什么?
传递一个函数可以让你在函数内访问到当前的 state 的值。因为 setState 的调用是分批的,所以你可以链式地进行更新,并确保它们是一个建立在另一个之上的,这样才不会发生冲突:
incrementCount() {
this.setState((state) => {
// 重要:在更新的时候读取 `state`,而不是 `this.state`。
return {count: state.count + 1}
});
}
handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 如果你现在在这里读取 `this.state.count`,它还是会为 0。
// 但是,当 React 重新渲染该组件时,它会变为 3。
}
setState 什么时候是异步的?
目前,在事件处理函数内部的 setState 是异步的。
例如,如果 Parent 和 Child 在同一个 click 事件中都调用了 setState ,这样就可以确保 Child 不会被重新渲染两次。取而代之的是,React 会将该 state “冲洗” 到浏览器事件结束的时候,再统一地进行更新。这种机制可以在大型应用中得到很好的性能提升。
这只是一个实现的细节,所以请不要直接依赖于这种机制。在以后的版本当中,React 会在更多的情况下静默地使用 state 的批更新机制。
为什么 React 不同步地更新 this.state?
如前面章节解释的那样,在开始重新渲染之前,React 会有意地进行“等待”,直到所有在组件的事件处理函数内调用的 setState() 完成之后。这样可以通过避免不必要的重新渲染来提升性能。
但是,你可能还是会想,为什么 React 不能立即更新 this.state,而不对组件进行重新渲染呢。
主要有两个原因:
这样会破坏掉 props 和 state 之间的一致性,造成一些难以 debug 的问题。原因如下
这样会让一些我们正在实现的新功能变得无法实现。 这个 GitHub 评论 深入了该特殊示例。
我应该使用一个像 Redux 或 MobX 那样的 state 管理库吗?
或许需要。
在添加额外的库之前,最好先了解清楚 React 能干什么。你也可以只使用 React 来构建出一个比较复杂的应用。
配置全局请求拦截器
普通
import axios from 'axios';
import React, { Component } from 'react';
import webConfig from './web_config'
import ReactDOM from 'react-dom';
import { message, Spin } from 'antd';
// 设置请求路径
axios.defaults.baseURL = webConfig.rootUrl;
// axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true; // 跨域配置
// 设置post请求头
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// 当前正在请求的数量
let requestCount = 0
// 全局显示loading
function showLoading () {
// requestCount为0,才创建loading, 避免重复创建
if (requestCount === 0) {
let dom = document.createElement('div')
dom.setAttribute('id', 'loading')
dom.style.position = 'fixed';
dom.style.top = '0px';
dom.style.left = '0px';
dom.style.background = 'rgba(0, 0, 0, 0.4)';
dom.style.display = 'flex';
dom.style.justifyContent = 'center';
dom.style.zIndex = '1000';
dom.style.alignItems = 'center';
dom.style.width = '100vw';
dom.style.height = '100vh';
document.body.appendChild(dom)
ReactDOM.render(<Spin tip="数据请求中,请稍后..." delay={300} size="large"/>, dom)
}
requestCount++
}
// 隐藏loading
function hideLoading () {
requestCount--
if (requestCount === 0) {
document.body.removeChild(document.getElementById('loading'))
}
}
// 请求前拦截,请求中设置isLoading = false, 则可以取消全局请求loading
axios.interceptors.request.use((config) => {
// 开启全局loading
if (config.headers.isLoading !== false) {
showLoading()
}
return config
}, (err) => {
// 取消全局请求loading
if (err.config.headers.isLoading !== false) {
hideLoading()
}
return Promise.reject(err)
});
// 返回后拦截,请求中设置isLoading = false, 则可以取消全局请求loading
axios.interceptors.response.use((res) => {
// 取消全局loading
if (res.config.headers.isLoading !== false) {
hideLoading()
}
return res
}, (err) => {
// 取消全局loading
if (err.config.headers.isLoading !== false) {
hideLoading()
}
// 可以配置访问异常的回调提示
if (err.message === 'Network Error') {
message.warning('网络连接异常!')
}
return Promise.reject(err)
});
const $http = (url = '', data = {}, type = 'GET', _config = {}) => new Promise((resolve, reject) => {
type = type.toUpperCase();
const config = Object.assign(_config, {
method: type,
url: url
});
const timestamp = new Date().getTime();
// get请求走正常
if (['GET'].includes(type)) {
config.params = data;
} else { // post增加请求头
Object.assign(config, {
headers: {
// 'Content-Type': 'multipart/form-data', // form 格式
'Content-Type': 'application/json', // json 格式
'token': localStorage.getItem('token')
}
});
// 封装Data => FormData
// const formdata = new FormData();
// for (let key in data) {
// formdata.append(key, data[key]);
// }
// config.data = formdata;
config.data = data;
}
axios(config).then((response) => {
// 失败
if (response && (response.data.code !== 200)) {
console.error('接口->请求未成功,接口:', response.config.url, '传参报错,参数:', JSON.parse(crypto.decrypt(JSON.parse(response.config.data).data)));
message.warning(response.data.msg);
resolve(response && response.data);
} else {
resolve(response && response.data);
}
})
.catch((err) => {
if (err.response) {
console.error('接口', err.config.url, '服务端报错,报错码->', err.response.status.toString(), '参数->', JSON.parse(err.config.data));
message.warning(err.response.data.msg);
} else {
console.error('接口', err.config.url, '服务器无响应,网络链接异常', JSON.parse(err.config.data));
message.warning(err.response.data.msg);
}
reject(err);
});
});
// formData 转 Json
let convert_FormData_to_json2 = (formData) => {
let objData = {};
formData.forEach((value, key) => objData[key] = value);
return JSON.stringify(objData);
};
export const $getData = async (url, data, _config = {}) => {
let res = await $http(url, data, 'GET', _config)
if (res.code === 200){
return Promise.resolve(res)
} else {
message.warning(res.data.msg);
return Promise.reject(res)
}
// return Promise.resolve(res)
};
export const $postData = async (url, data, _config = {}) => {
let res = await $http(url, data, 'POST', _config)
if (res.code === 200){
if (res.data) { // 当有返回才解析
res.data = JSON.parse(crypto.decrypt(res.data));
}
return Promise.resolve(res)
} else {
message.warning(res.data.msg);
return Promise.reject(res)
}
// return Promise.resolve(res)
};
配合AES加密
这里的Crypto文件可以在我的另外一篇文章里获取从零开始构建前后端AES加密通信
import axios from 'axios';
import React, { Component } from 'react';
import webConfig from './web_config'
import ReactDOM from 'react-dom';
import crypto from './Crypto';
import { message, Spin } from 'antd';
// 设置请求路径
axios.defaults.baseURL = webConfig.rootUrl;
// axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true; // 跨域配置
// 设置post请求头
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// 当前正在请求的数量
let requestCount = 0
// 全局显示loading
function showLoading () {
// requestCount为0,才创建loading, 避免重复创建
if (requestCount === 0) {
let dom = document.createElement('div')
dom.setAttribute('id', 'loading')
dom.style.position = 'fixed';
dom.style.top = '0px';
dom.style.left = '0px';
dom.style.background = 'rgba(0, 0, 0, 0.4)';
dom.style.display = 'flex';
dom.style.justifyContent = 'center';
dom.style.zIndex = '1000';
dom.style.alignItems = 'center';
dom.style.width = '100vw';
dom.style.height = '100vh';
document.body.appendChild(dom)
ReactDOM.render(<Spin tip="数据请求中,请稍后..." delay={300} size="large"/>, dom)
}
requestCount++
}
// 隐藏loading
function hideLoading () {
requestCount--
if (requestCount === 0) {
document.body.removeChild(document.getElementById('loading'))
}
}
// 请求前拦截,请求中设置isLoading = false, 则可以取消全局请求loading
axios.interceptors.request.use((config) => {
// 开启全局loading
if (config.headers.isLoading !== false) {
showLoading()
}
return config
}, (err) => {
// 取消全局请求loading
if (err.config.headers.isLoading !== false) {
hideLoading()
}
return Promise.reject(err)
});
// 返回后拦截,请求中设置isLoading = false, 则可以取消全局请求loading
axios.interceptors.response.use((res) => {
// 取消全局loading
if (res.config.headers.isLoading !== false) {
hideLoading()
}
return res
}, (err) => {
// 取消全局loading
if (err.config.headers.isLoading !== false) {
hideLoading()
}
// 可以配置访问异常的回调提示
if (err.message === 'Network Error') {
message.warning('网络连接异常!')
}
return Promise.reject(err)
});
const $http = (url = '', data = {}, type = 'GET', _config = {}) => new Promise((resolve, reject) => {
type = type.toUpperCase();
const config = Object.assign(_config, {
method: type,
url: url
});
const timestamp = new Date().getTime();
// get请求走正常
if (['GET'].includes(type)) {
// config.params = data;
config.params = {}
config.params.data = crypto.encrypt(JSON.stringify(data));
config.params.timestamp = timestamp.toString()
} else { // post增加请求头
Object.assign(config, {
headers: {
// 'Content-Type': 'multipart/form-data',
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
}
});
// 封装Data => FormData
// const formdata = new FormData();
// for (let key in data) {
// formdata.append(key, data[key]);
// }
// config.data = formdata;
config.data = {}
config.data.data = crypto.encrypt(JSON.stringify(data));
config.data.timestamp = timestamp.toString();
console.log('解密参数', JSON.parse(crypto.decrypt(config.data.data)))
}
axios(config).then((response) => {
// 失败
if (response && (response.data.code !== 200)) {
console.error('接口->请求未成功,接口:', response.config.url, '传参报错,参数:', JSON.parse(crypto.decrypt(JSON.parse(response.config.data).data)));
message.warning(response.data.msg);
resolve(response && response.data);
} else {
resolve(response && response.data);
}
})
.catch((err) => {
if (err.response) {
console.error('接口', err.config.url, '服务端报错,报错码->', err.response.status.toString(), '参数->', JSON.parse(err.config.data));
message.warning(err.response.data.msg);
} else {
console.error('接口', err.config.url, '服务器无响应,网络链接异常', JSON.parse(err.config.data));
message.warning(err.response.data.msg);
}
reject(err);
});
});
// formData 转 Json
let convert_FormData_to_json2 = (formData) => {
let objData = {};
formData.forEach((value, key) => objData[key] = value);
return JSON.stringify(objData);
};
export const $getData = async (url, data, _config = {}) => {
let res = await $http(url, data, 'GET', _config)
if (res.code === 200){
if (res.data) {// 当有返回才解析
res.data = JSON.parse(crypto.decrypt(res.data));
}
return Promise.resolve(res)
} else {
message.warning(res.data.msg);
return Promise.reject(res)
}
// return Promise.resolve(res)
};
export const $postData = async (url, data, _config = {}) => {
let res = await $http(url, data, 'POST', _config)
if (res.code === 200){
if (res.data) { // 当有返回才解析
res.data = JSON.parse(crypto.decrypt(res.data));
}
return Promise.resolve(res)
} else {
message.warning(res.data.msg);
return Promise.reject(res)
}
// return Promise.resolve(res)
};