react 总结
0. 创建项目:npx create-react-app my-app
1. 样式: https://blog.csdn.net/weixin_37620905/article/details/86567861
2. componentWillReceiveProps(newProps) 组件接收到新的 props 时触发
3. https://developer.github.com/v3/ gitHub 开发者API
4. 通过消息订阅模式 pubsub-js 组件之间传递参数
5. 按需打包:
方法一: 手动引入
import DatePicker from 'antd-mobile/lib/date-picker'; // 加载 JS
import 'antd-mobile/lib/date-picker/style/css'; // 加载 CSS
import 'antd-mobile/lib/date-picker/style'; // 加载 LESS
方法二: 新建 .babelrc 文件 【不建议使用,一堆配置看不懂】
1. npm install babel-plugin-import --save-dev
2. npm run eject 弹出webpack配置文件
3. webpack配置文件新增配置
{
"plugins": [
["import", { "libraryName": "antd-mobile", "style": "css" }] // `style: true` 会加载 less 文件
]
}
方法三: 使用 react-app-rewired (react-scripts的封装) 插件,修改启动方式
1. npm install react-app-rewired customize-cra --save-dev
npm install babel-plugin-import --save-dev
2. 新建 config-overrides.js 文件
const { override, fixBabelImports ,addWebpackExternals ,addWebpackAlias ,addLessLoader } = require('customize-cra');
const path = require("path")
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
const myPlugin = [
new UglifyJsPlugin(
{
uglifyOptions: {
warnings: false,
compress: {
drop_debugger: true,
drop_console: true
}
}
}
)
]
module.exports = override(
fixBabelImports('import', { //配置按需加载
libraryName: 'antd-mobile',
// libraryDirectory: 'es',
style: true,
}),
addWebpackExternals({ //不做打包处理配置,如直接以cdn引入的
echarts: "window.echarts",
// highcharts:"window.highcharts"
}),
addWebpackAlias({ //路径别名
'@': path.resolve(__dirname, 'src'),
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: {
"@brand-primary": "#1cae82", // 正常
"@brand-primary-tap": "#000", // 按下
}
}),
(config)=>{ //暴露webpack的配置 config ,evn
// 去掉打包生产map 文件
// config.devtool = config.mode === 'development' ? 'cheap-module-source-map' : false;
if(process.env.NODE_ENV==="production") config.devtool=false;
if(process.env.NODE_ENV!=="development") config.plugins = [...config.plugins,...myPlugin]
//1.修改、添加loader 配置 :
// 所有的loaders规则是在config.module.rules(数组)的第二项
// 即:config.module.rules[2].oneof (如果不是,具体可以打印 一下是第几项目)
// 修改 sass 配置 ,规则 loader 在第五项(具体看配置)
const loaders = config.module.rules.find(rule => Array.isArray(rule.oneOf)).oneOf;
// console.log(loaders)
loaders[9].use.push({
loader: 'less-loader',
options: {
// resources: path.resolve(__dirname, 'src/asset/base.less')//全局引入公共的scss 文件
},
})
loaders[1] = {
test: [ /\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/ ],
use: [{
loader: "url-loader",
options: {
limit: 10 * 1024,
name: 'static/images/[hash:6].[ext]',
fallback: 'file-loader',
publicPath: '../',
esModule: false, // 新添加
}
}]
}
return config
}
);
3. 修改package.json 启动命令
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
4. 更改引入方式
+ import { Button } from 'antd-mobile';
6. redux 默认不支持异步
1. redux-thunk (redux 的异步中间件)
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk' // 异步Action插件
const store = createStore(counter, applyMiddleware(thunk))
export default store
7.react-redux
1. 简化 react 中 redux 的使用
2. redux-devtools-extension 开发工具,搭配 chrom 插件 redux-devtools 使用; npm i --save-dev redux-devtools-extension
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk' // 异步Action插件
import { composeWithDevTools } from 'redux-devtools-extension'
import { counter } from './reducers'
const store = createStore(counter, composeWithDevTools(applyMiddleware(thunk)))
export default store
8. 运行打包后的项目
npm run build
npm i serve -g
serve build
9. 按需引入 antd-mobile 使用less
1. https://www.cnblogs.com/beyonds/p/11441914.html
2. 引入 less 报错版本问题
"less": "^2.7.3",
"less-loader": "^4.1.0"
10. react 图片本地引入。默认不支持 [commonJS] 的 require 引入模块。默认是 [es] import 模式。
1. 解决:在 config-overrides.js 文件中增加 url 配置
loaders[1] = {
test: [ /\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/ ],
use: [{
loader: "url-loader",
options: {
limit: 10 * 1024,
name: 'static/images/[hash:6].[ext]',
fallback: 'file-loader',
publicPath: '../',
esModule: false, // 新添加
}
}]
}
11. 跨域代理
1. package.json 中配置 "proxy": "http://localhost:5000"
---------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------
13. Hook 函数组件
hook 的本质是函数(钩子函数),该函数可以让 react 的函数组件中带入 【state】 及【生命周期等特性】
1. state hook: useState
使用:1. [<取值>, <设值>] = useState(<初始值>) : const [isHungry, setIsHungry] = useState(true)
2. 创建一个“状态变量”,并赋予一个初始值。上面例子中的状态变量是isHungry,初始值为true。
同时创建一个函数用于设置此状态变量的值——setIsHungry
2. effect hook:useEffect
1. 和 componentDidMount、componentDidUpdate、 componentWillUnmount 具有相同的用途,在函数组件中充当生命周期
2. 默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候
3. React 在完成 DOM 的更改后会运行“副作用”函数
4. useEffect 函数中可以访问到 state 和 peops
5. 可以 return 一个函数来做清除操作
6. 示例 useEffect(() => {
// 操作
return () => {
// 清除操作
}
});
7. useEffect(参数1, 参数2)
参数1: 函数
参数2: 数组,hook 执行的变量,参数2发生变化时才执行。参数2是空数组,只执行【一次】
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, [props.friend.id]); // 仅在 props.friend.id 发生变化时,重新订阅
3. 自定义 hook
1. 可复用的【状态或者操作】提取出来一个【函数】作为自定义 hook 函数
2. 每个组件的 state 是独立的,重复调用 hook 函数不会相互影响
3. 函数名 use 开头
4. useRef 等同于 vue 的 ref
1. 使用: const inputEl = useRef(null);
<input ref={inputEl} type="text" />
2. 取值:
inputEl.current
5. useLayoutEffect
1. DOM 变更后调用
2. 用于读取 DOM 布局
5. useContext 不常用
const locale = useContext(LocaleContext);
const theme = useContext(ThemeContext);
6. useReducer 不常用
const [todos, dispatch] = useReducer(todosReducer);
7. useLayoutEffect 测量布局
8. useCallback
---------------------------------------------------------------------------------------------------------------------------------------------------
14. context
1. 目的:共享组件数之间全局的数据,比如 theme,语言
2. 使用:
----------------------------------------------------------------------------------------------------------------------------------------------------
15. refs
3种方式:
1. 字符串字面量形式
定义: <input ref={this.input}>
获取:const {input} = this.refs
2. 行内回调函数形式,调用n+1次
定义: <input ref={(input) => {this.input = input}}>
3. 定义回调函数形式
定义: <input ref={this.inputRef}>
inputRef = (input) => {
this.input = input
}
4. createRef 方式
定义:const ref = React.createRef();
使用:<button ref={ref}>
ref 向下传递:
1. React.forwardRef 来获取传递给它的 ref
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
2. 在高阶组件中传递
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// 注意 React.forwardRef 回调的第二个参数 “ref”。
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
// 然后它就可以被挂载到被 LogProps 包裹的子组件上。
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
3. ref 不会在 props 中向下传递,react 做了特殊处理
----------------------------------------------------------------------------------------------------------------------------------------------------
16. 高阶组件
1. 高阶组件是参数为组件,返回值为新组件的函数
function logProps(WrappedComponent) {
return class extends React.Component {
componentDidUpdate(prevProps) {
console.log('Current props: ', this.props);
console.log('Previous props: ', prevProps);
}
render() {
// 将 input 组件包装在容器中,而不对其进行修改。Good!
return <WrappedComponent {...this.props} />;
}
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------
17. render props
1. render 属性传递一个函数,返回(return)一个react组件;
2. 目的:在组件内部想渲染的地方,动态渲染自己想要的组件
3. 例子:
1. 接受:
class Mouse extends React.Component {
render() {
return (
<div style={{ height: '100vh' }}>
{/*
使用 `render`prop 动态决定要渲染的内容,
而不是给出一个 <Mouse> 渲染结果的静态表示
*/}
{this.props.render(this.state)}
</div>
);
}
}
2. 传递:
// 如果你出于某种原因真的想要 HOC,那么你可以轻松实现
// 使用具有 render prop 的普通组件创建一个!
function withMouse(Component) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Component {...this.props} mouse={mouse} />
)}/>
);
}
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------
18. PropTypes 类型检查
---------------------------------------------------------------------------------------------------------------------------------------------------
19. ReactDOM.createPortal(child, container)
1. 将子节点渲染到 DOM 节点中
20. ReactDOM.unmountComponentAtNode(container)
1. 从 DOM 中卸载组件,会将其事件处理器(event handlers)和 state 一并清除
---------------------------------------------------------------------------------------------------------------------------------------------------
21. react-router
1. import { browserHistory } from 'react-router'
const routeConfig = [
{ path: '/',
component: App,
indexRoute: { component: Dashboard },
childRoutes: [
{ path: 'about', component: About },
{ path: 'inbox',
component: Inbox,
childRoutes: [
{ path: '/messages/:id', component: Message },
{ path: 'messages/:id',
onEnter: function (nextState, replaceState) {
replaceState(null, '/messages/' + nextState.params.id)
}
}
]
}
]
}
]
React.render(<Router history={browserHistory} routes={routeConfig} />, document.body)
----------------------------------------------------------------------------------------------------------------------------------------------------
22. 组件 API:
设置状态:setState
替换状态:replaceState
设置属性:setProps
替换属性:replaceProps
强制更新:forceUpdate
获取DOM节点:findDOMNode
判断组件挂载状态:isMounted
----------------------------------------------------------------------------------------------------------------------------------------------------
23. class 组件生命周期的方法有:
componentWillMount 在渲染前调用,在客户端也在服务端。【17 已废弃】
componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
componentWillUnmount在组件从 DOM 中移除之前立刻被调用。
------------------最新版本----------------
初始化阶段:
1. construst
2. static getDerivedStateFromProps(prevState, nextProps)
3. render
4. componentDidMount
更新阶段:
1. static getDerivedStateFromProps(prevState, nextProps)
2. shouldComponentUpdate
3. render
4. getSnapshotBeforeUpdate(prevProps, prevState)
5. componentDidUpdate
组件卸载阶段:
1. componentWillUnmount
生命周期报错会被以下函数捕获:
1. componentDidCatch(error, errorInfo)
2. static getDerivedStateFromError()
----------------------------------------------------------------------------------------------------------------------------------------------------
24. 国际化
方式1. 使用 i18next react-i18next 库
1. 初始化
i18n.use(initReactI18next).init({
resources,
lng: sessionStorage.lang || 'cn', //设置当前语言
keySeparator: '.', // keySeparator: false, 不允许 t('home.age') / '.' 支持t('home.age')
interpolation: {
escapeValue: false
}
})
2. 配置语言文件
const resources = {
en:{
translation: en,
},
cn: {
translation: cn
}
}
3. 在组件中使用(4种方法)
1. 函数组件中使用
import { useTranslation } from 'react-i18next'
function Home () {
const {t, i18n} = useTranslation() // 只能在函数组件使用
}
2. 类组件中使用
import { withTranslation } from 'react-i18next'
@withTranslation()
class Home extends React.Component{}
被withTranslation装饰的组件就能在 props 中拿到 i18n 和 t 函数
3. Translation 组件
4. Trans 组件
方式2. 使用 react-intl react-intl-universa 库
切换语言的函数:i18n.changeLanguage(lang)
语言切换监听:
i18n.on('languageChanged', (e) => {
window.location.reload()
})
需要国际化的类型:
1. 页面中的写死的 汉字
2. antd 组件中的隐式的 placeholder,提示信息等
3. antd 中的 title
4. 后台接口返回的提示语
5. 后台接口返回的数据(枚举等...)
遗留问题:
1. 语言文件多层级无法翻译?
解决: 初始化时 keySeparator: '.'
-----------------------------------------------------------------
25. react 允许项目class组件中使用注解
在 package.json中添加:
"babel": {
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true //允许项目class组件中使用注解
}
]
]
}
------------------------------------------------------------------
26. Portals
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的的方案
ReactDOM.createPortal(
this.props.children,
domNode
)
--------------------------------------------------------------------------
27. react diff 算法
1. 对比不同类型的元素。比如 span -> div <Person> -> <Dog>, 销毁react树,重新构建
2. 对比同一类型元素,仅属性变化。比如 <div className="before" title="stuff" /> -> <div className="after" title="stuff" />
仅比对及更新有改变的属性。
3. 对比同类型React组件元素(组件更新)。组件实例会保持不变,因此可以在不同的渲染时保持 state 一致。React 将更新该组件实例的 props 。
4. 对子元素递归。引入 keys 解决递归开销大问题。
--------------------------------------------------------------------------
28. Web Components
浏览器支持的一种组件化技术,shadow DOM
-----------------------------------------------------------------------------
29. 函数节流方式
1. 节流:基于时间的频率来进行抽样更改 (例如 _.throttle)
2. 防抖:一段时间的不活动之后发布更改 (例如 _.debounce)
3. requestAnimationFrame 节流:基于 requestAnimationFrame 的抽样更改 (例如 raf-schd)
----------------------------------------------------------------------------------------------------------------------------------------------------
1. MongoDB
C:\Program Files\MongoDB\Server\4.4\bin
net start MongoDB
net stop MongoDB
2. 查找某个包
npm ls 【包名称】-g
npm ls 【包名称】
-------------------------------------------------------------
F:\node-demo :
bee-job-serve express-demo
E:\react-project:
antd-demo react-news