include note.js 运行demohttps://hahabazinga.github.io/react-demo/
- 用
BrowserRouter
容纳根元素
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'));
App
组件里使用main
组件
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">title</h1>
</header>
<Main/>
</div>
);
}
}
- 需要在哪个组件进行路由,就在该组件里使用
Route
(Switch
包裹则只渲染第一个匹配的组件),这里是main
import { Route, Switch} from 'react-router-dom'
import React from 'react'
import Home from '../components/Home'
import About from '../components/About'
const Main = () => (
<main>
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/about/:number' component={ About } />
</Switch>
</main>
)
export default Main
- 路由跳转
// Link
<Link key={item} to={`/about/${item}`}>about{item}</Link>
// this.props.history.push
this.props.history.push('/about/1')
- 路由参数获取:
this.props.match.params.number
exact
:路径完全匹配才会渲染
@media
原理:window.matchMedia()
检查css
中的媒体查询
var result = window.matchMedia('(max-width: 700px)');
if (result.matches) {
console.log('页面宽度小于等于700px');
} else {
console.log('页面宽度大于700px');
}
- 单行省略号
.a{
overflow: hidden;
text-overflow: ellipsis;
white-space: no-wrap;
}
- 多行省略号
.b{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow:hidden;
}
1px
.scale-1px{
position: relative;
margin-bottom: 20px;
border:none;
}
.scale-1px:after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
localstorage
一般5M,使用前最好检查
if (window.localStorage) {
try {
localStorage.setItem('bla', 'bla');
} catch (e) {
if (e.name === 'QUOTA_EXCEEDED_ERR' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
// todo
} else {
// todo
}
}
}
var webpack = require("webpack");
module.exports = {
entry: { a: "./a", b: "./b" },
output: { filename: "[name].js" },
plugins: [ new webpack.optimize.CommonsChunkPlugin("init.js") ]
}
当有多个入口的时候,CommonsChunkPlugin
会把 a
,b
模块公共依赖的模块抽离出来
- 解析
webpack
配置参数,合并从shell
传入和webpack.config.js
文件里配置的参数,生产最后的配置结果。 - 注册所有配置的插件,好让插件监听
webpack
构建生命周期的事件节点,以做出对应的反应。 - 从配置的
entry
入口文件开始解析文件构建AST
语法树,找出每个文件所依赖的文件,递归下去。 - 在解析文件递归的过程中根据文件类型和
loader
配置找出合适的loader
用来对文件进行转换。 - 递归完后得到每个文件的最终结果,根据
entry
配置生成代码块chunk
。 - 输出所有
chunk
到文件系统。 需要注意的是,在构建生命周期中有一系列插件在合适的时机做了合适的事情,比如UglifyJsPlugin
会在loader
转换递归完后对结果再使用UglifyJs
压缩覆盖之前的结果。
class EndWebpackPlugin {
constructor(doneCallback, failCallback) {
this.doneCallback = doneCallback;
this.failCallback = failCallback;
}
apply(compiler) {
// 监听webpack生命周期里的事件,做相应的处理
compiler.plugin('done', (stats) => {
this.doneCallback(stats);
});
compiler.plugin('failed', (err) => {
this.failCallback(err);
});
}
}
module.exports = EndWebpackPlugin;
- 使用
babylon
解析器对输入的源代码字符串进行解析并生成初始AST
(File.prototype.parse
) - 利用
babel-traverse
这个独立的包对AST
进行遍历,并解析出整个树的path
,通过挂载的metadataVisitor
读取对应的元信息,这一步叫set AST
过程 transform
过程:遍历AST
树并应用各transformers(plugin)
生成变换后的AST
树- 利用
babel-generator
将AST
树输出为转码后的代码字符串 babel原理分析
setState
只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout
中都是同步的。setState
的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数setState(partialState, callback)
中的callback
拿到更新后的结果。setState
的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout
中不会批量更新,在“异步”中如果对同一个值进行多次setState
,setState
的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState
多个不同的值,在更新时会对其进行合并批量更新。
- 通过
commander
获取项目名 - 检查项目名
- 用项目名在当前目录下创建文件夹,并在里面初始化一个
package.json
文件 - 进入项目目录,安装
react
、react-dom
、react-scripts
依赖 - 调用
react-scripts
的init
初始化项目 - 结束
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
// 读取写好的 loading 态的 html 和 css
var loading = {
html: fs.readFileSync(path.join(__dirname, './loading.html')),
css: '<style>' + fs.readFileSync(path.join(__dirname, './loading.css')) + '</style>'
}
var webpackConfig = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'xxxx.html',
template: 'template.html',
loading: loading
})
]
};
复制代码然后在模板中引用即可:
<!DOCTYPE html>
<html lang="en">
<head>
<%= htmlWebpackPlugin.options.loading.css %>
</head>
<body>
<div id="root">
<%= htmlWebpackPlugin.options.loading.html %>
</div>
</body>
</html>
<></>
不能接受任何属性
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</React.Fragment>
)
)}
</dl>
)
}
key
是<React.Fragment>
标签唯一接受的属性
render() {
// React mounts a new div and renders the children into it
return (
<div>
{this.props.children}
</div>
)
}
render() {
// React does *not* create a new div. It renders the children into `domNode`.
return ReactDOM.createPortal(
// Any valid React child: JSX, strings, arrays, etc.
this.props.children,
// `domNode` is any valid DOM node, regardless of its location in the DOM.
domNode
)
}
对于父组件,也就是context
的生产者,需要通过一个静态属性childContextTypes
声明提供给子组件的Context对象的属性,并实现一个实例getChildContext
方法,返回一个代表Context
的纯对象 (plain object
) 。
// 声明Context对象属性
static childContextTypes = {
propA: PropTypes.string,
methodA: PropTypes.func
}
// 返回Context对象,方法名是约定好的
getChildContext () {
return {
propA: 'propA',
methodA: () => { }
}
}
子组件需要通过一个静态属性contextTypes
声明后,才能访问父组件Context
对象的属性
// 声明需要使用的Context属性
static contextTypes = {
propA: PropTypes.string
}
const {
propA,
methodA
} = this.context
// 属于微任务
const callback = function(mutation) { ... }
const mb = new mutationObserver(callback);
mb.observe(domNode, {
childList: true
}), // 注册观察
ma.disconnect() // 停止观察
Last-Modified
使用文件最后修改作为文件标识值,它无法处理文件一秒内多次修改的情况,而且只要文件修改了哪怕文件实质内容没有修改,
也会重新返回资源内容;ETag
作为“被请求变量的实体值”,其完全可以解决Last-Modified
头部的问题,但是其计算过程需要耗费服务器资源