1.immutable
連續(xù)看了兩三篇關(guān)于immutable.js的文章,傳統(tǒng)的object和array等引用類型是mutable數(shù)據(jù),就是當(dāng)賦值的時(shí)候,指向同個(gè)內(nèi)存,這在react更新機(jī)制里面就會出現(xiàn)個(gè)問題,引用是相同的,react purecomponent就會檢測不出前后兩個(gè)props的不同部分,就不會re-render,而React.Component是可以檢測出來props的更新的,然后就會re-render,比如一個(gè)組件的props改變(數(shù)據(jù)流是單向的)該組件的props改變只需要其對應(yīng)的父組件更新就可以了,不需要該組件的兄弟組件及其子組件更新,因?yàn)樵鷍s引用類型共享內(nèi)存,這些組件都會更新,這是我們不想看到的,所以引入了immutable.js共享部分內(nèi)存,把直接相關(guān)的節(jié)點(diǎn)更新就可以了。
Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐
react Performance Tools 入門
使用immutable優(yōu)化React
2. 模塊或者組件按需加載
React Loadable 簡介
webpack 構(gòu)建性能優(yōu)化策略小結(jié)
react項(xiàng)目優(yōu)化之webpack
react-router按需加載(V4版)
使用import()實(shí)現(xiàn)組件的按需加載
根據(jù)點(diǎn)擊的鏈接會在head標(biāo)簽里插入
發(fā)現(xiàn)個(gè)很有趣的現(xiàn)象,點(diǎn)擊About鏈接或者DashBoard鏈接兩個(gè)組件相互切換,在同個(gè)頁面的路由組件,路由切換的話,前面一個(gè)渲染好的組件會Unmount,即被卸載
例如路由about->dashboard,About組件會被卸載(componentWillUnmount被調(diào)用),DashBoard被裝載(componentWillMount被調(diào)用),
由下圖可以看出,路由導(dǎo)航到dashboard的時(shí)候About組件并沒有被包含在其Route組件里,也就是切換路由的時(shí)候About被卸載了,移出了dom
倉庫:assassin / react-starter
參考:
在react-router4中進(jìn)行代碼拆分(基于webpack)
HTML5 <script>元素async,defer異步加載
3.試讀react-redux源碼
本文的react-redux代碼本版為5.0.6
阮一峰的Redux 入門教程(三):React-Redux 的用法
class VisibleTodoList extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();
// ...
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}
React-Redux
自動生成的容器組件的代碼,就類似上面這樣,從而拿到store
這句話不是很理解,對比了下官方給出的代碼:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
default:
throw new Error('Unknown filter: ' + filter)
}
}
const mapStateToProps = (state) => ({
todos: getVisibleTodos(state.todos, state.visibilityFilter)
})
const mapDispatchToProps = {
onTodoClick: toggleTodo
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
和大神說的自動生成的容器組件的代碼完全不同,現(xiàn)在的理解應(yīng)該是connect以后得到的容器組件的代碼,而不是現(xiàn)在我們看到的官網(wǎng)的容器組件的代碼
今天看到了connectAdvanced.js
的最后一句卡住了return hoistStatics(Connect, WrappedComponent)
import hoistStatics from 'hoist-non-react-statics'
來自于hoist-non-react-statics具體干啥用的還不清楚,搜索它怎么用的時(shí)候發(fā)現(xiàn)了官網(wǎng)高階組件里面提到了這個(gè)庫,于是再次看了遍高階組件的用法,如是說:高階組件是一個(gè)函數(shù),能夠接受一個(gè)組件并返回一個(gè)新的組件,結(jié)合實(shí)際的react-redux的connect功能,
import TodoList from '../components/TodoList'
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
connect.js
connect.js調(diào)用了connectAdvanced.js
connectAdvanced.js
那么如果從高階組件的定義高階組件是一個(gè)函數(shù),能夠接受一個(gè)組件并返回一個(gè)新的組件來看connectAdvanced.js
中的wrapWithConnect
函數(shù)就是高階組件,它接受了一個(gè)WrappedComponent
組件返回了一個(gè)<Connect(TodoList)>...</Connect(TodoList)>
新的組件
displayName其實(shí)是組件的一個(gè)靜態(tài)屬性,如果在組件中定義則有,否則不會有該屬性
靜態(tài)屬性在es6的不同版本有不同的定義方式:
export default class MainSection extends Component {
static propTypes = {//先進(jìn)的一種
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}
}
//原始的一種
MainSection.propTypes={
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}
到目前的理解,使用高階組件的目的有
- 抽取很多組件的公共方法和屬性,類似于之前的mixin
- 返回的新組件必須保留原始組件的功能(包括原始組件的靜態(tài)方法和靜態(tài)屬性)
connectAdvanced.js
import hoistStatics from 'hoist-non-react-statics'
export default function connectAdvanced(){
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
}
Connect.WrappedComponent = WrappedComponent
Connect.displayName = displayName
Connect.childContextTypes = childContextTypes
Connect.contextTypes = contextTypes
Connect.propTypes = contextTypes
if (process.env.NODE_ENV !== 'production') {
}
return hoistStatics(Connect, WrappedComponent)//原始組件的所有靜態(tài)方法全部拷貝給新組件
}
}
}
上下文(Context)
react-redux源碼分析
react-redux源碼分析
react-redux 源碼解析
一個(gè)有意思的發(fā)現(xiàn):
class Animal{
constructor(){
this.age=""
}
showAge(){
console.info(this.age)
}
getName=()=>{
return "name"
}
}
使用ts編譯為js
var Animal = /** @class */ (function () {
function Animal() {
this.getName = function () {
return "name";
};
this.age = "";
}
Animal.prototype.showAge = function () {
console.info(this.age);
};
return Animal;
}());
4.高階組件的兩種實(shí)現(xiàn)方式
看這篇文章帶著三個(gè)問題一起深入淺出React高階組件的時(shí)候發(fā)現(xiàn)有個(gè)有趣的現(xiàn)象:父組件可以直接調(diào)用子組件的實(shí)例方法,這在Java中是不可能的,具體可查看Java 中父類怎么調(diào)用子類的方法?,這篇文章指出可以使用反射的方式,js真的不按套路出牌啊
深入理解 React 高階組件
React進(jìn)階之高階組件
React高階組件探究
React 高階組件(HOC)入門指南
5.木偶組件和智能組件
在 2017 年學(xué)習(xí) React + Redux 的一些建議(上篇)
react root組件下面應(yīng)該放什么組件?
6.按需加載 包括saga
react結(jié)合redux和react-router開發(fā)大型應(yīng)用實(shí)現(xiàn)按需加載(code spliting)
React Router v4 之代碼分割:從放棄到入門
7.在代碼提交之前需要對代碼進(jìn)行l(wèi)int和語法檢查
需要用到庫:
okonet/lint-staged
typicode/husky
prettier/prettier
從React腳手架工具學(xué)習(xí)React項(xiàng)目的最佳實(shí)踐(上):前端基礎(chǔ)配置
前端開發(fā)如何讓持續(xù)集成/持續(xù)部署(CI/CD)跑起來
github 集成測試
前端開源項(xiàng)目持續(xù)集成三劍客
8.用js的方式改變子組件的props
import RadioButton from './radioButton'
children = React.Children.map(children, (child: any) => {
if (child.type === RadioButton) {
return React.cloneElement(child, {
prefixCls: radioType === 'text' ? 'radio-text' : 'radio-button', //手動改變了prefixCls props
})
} else {
return child
}
})