性能优化
1.改变作用域的方法 bind 都放在constructor方法里面,只会执行一次,避免子组件的无谓渲染;
2.setState内置优化,异步操作,可以把多次多次数据改变,结合为一次,降低虚拟DOM的比对评率;
3.虚拟DOM比对;
4.同层比对;
5.key值;
6.Diff算法;
7.借助shouldComponentUpdate函数,避免无谓的虚拟DOM比对,阻止render函数执行;
8.最好使用无状态组件(没有生命周期函数,也不会生成组件的实例)
生命周期
初始化数据加载过程:
`constructor` // 初始化数据
`componentWillMount` //在组件即将被挂载到页面的时候执行
`render ` // 组件更新 更改state props都会执行
`componentDidMount` //在组件被挂载到页面后执行
更新数据过程:
`shouldComponentUpdate` // 组件再被更新之前执行,必须return一个布尔值,如果返回false则不更新组件
`componentWillUpdate` // 组件更新之前动执行
`render` // 更新组件
`componentDidUpdate` // 组件更新之后执行
父子组件的数据传递:
`componentWillReceiveProps`
// 当一个组件要从父组件接受参数
// 只要父组件的render函数被重新执行了,子组件的这个生命周期函数才会执行
// 如果这个组件第一次存在于父组件中,不会执行
// 如果这个组件第二次存在于父组件中,才会执行
组件消失:
`componentWillUnmount` //当这个组件即将被从页面中剔除的时候,会被执行
css插件
react-transition-group
组件
Transition CSSTransition TransitionGroup
通讯
父组件向子组件通过数据绑定的形式进行通讯
子组件向父组件通过调用父组件传递过来的方法去操作父组件的数据
prop-types 插件 父子组件 属性预定和默认值
Redux
ReactComponents (借书人)
ActionCreaction(你要借什么书,要说的话)
Stote (图书馆的管理员)
Reducers (记录本,看到要借什么书,去里面查找,做出相应的处理)
概念
store是唯一的
只有store能改变自身的内容
reducers 必须是纯函数(纯函数就是,给定固定的输入,就一定会有固定的输出,且不会有任何的副作用)
API
createStore() 会创建一个store,
store.dispatch() 会派发一个action 并传递给store,
store.getState() 获取store里面所有的内容,
store.subscribe() 在store发生改变的时候触发,可以接受一个回调方法
文件
immutable.js 对数据进行管理
store
// index.js 创建store
import { createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';
import thunk from 'redux-thunk';
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const middleware = [thunk];
const enhancer = composeEnhancers(
applyMiddleware(...middleware),
);
const store = createStore( reducer, enhancer);
export default store
reducer.js 存储原始数据 及更改数据的逻辑
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM ,DEL_LIST} from './actionTypes'
const defaultState = {
inputValue: '',
list: []
};
// reducer 可以接受state ,但是绝不能修改state
export default (state = defaultState, action) => {
if(action.type === ADD_TODO_ITEM){
const newState = JSON.parse(JSON.stringify(state));
newState.list = [...newState.list,newState.inputValue];
// newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState
}
return state;
}
actionTypes.js 存储action type
export const ADD_TODO_ITEM = 'add_todo_item';
actionCreators.js 存储action
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM ,DEL_LIST} from './actionTypes'
export const getDelListAction = (index) => ({
type: DEL_LIST,
index
});
export const initListAction = (data) => ({
type: INIT_LIST_ACTION,
data
});
export const getTodoList = () => {
return (dispatch) => {
axios.get('/api/todolist').then((res) =>{
const data = res.data;
const action = initListAction(data)
dispatch(action)
})
}
}
组件内
import store from './store'
import { getDelListAction,getTodoList} from './store/actionCreators'
constructor(props){
super(props);
this.state = store.getState();
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
componentDidMount() {
const action = getTodoList();
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleItemDelete(index) {
const action = getDelListAction(index);
store.dispatch(action);
}
组件 普通组件 UI组件 容器组件 无状态组件 中间件(redux-thunk redux-saga)
插件 redux-tools
vue 与react 之间的差异
vue 双向数据绑定 双向数据流 支持指令
react 单项数据流 没有指令
虚拟DOM
1. state数据
2. JSX 模板
3. 数据 + 模板 生成的虚拟DOM(虚拟DOM就是一个JS对象,用来描述真实的DOM)(损耗了性能)
['div',{id:'abc'},['span','','hello world']]
4. 用虚拟DOM的结构生成真实的DOM,显示<div id='abc'><span>hello worid</span></div>
5. state 发生变化
6. 数据 + 模板 生成的虚拟DOM (极大的提升了性能)
['div',{id:'abc'},['span','','bye bye']]
7. 比较原始虚拟DOM和新的虚拟DOM的区别,找到区别是SPAN中的内容(极大的提升了性能)
8. 直接操作DOM,改变span中的内容
优点:
1. 性能的提升
2. 它使得跨端应用得以实现, React Native
setState
是异步执行,如果连续改变,会合并为一次虚拟DOM比对
Diff算法
同级比较(算法简单,速度快 ) 从第一层虚拟DOM进行比对,如果比对有差异,自身包括子级节点全部替换
react 15和16的区别
- 语法区别
15---
const App = React.createClass({});
16---
class App extends React.Component{}
- propType和getDefaultProps
15---
const App = React.createClass({
propTypes:{
name:React.PropTypes.string.isRequried
},
getDefaultProps() {
return {
name:"aaa"
}
},
render(){}
});
16---
class App extends React.Component{
static propTypes = {
name :React.PropTypes.string.isRequried
};
static defaultProps = {
name:"aaa"
};
constructor(props){
super(props)
}
render(){}
}
- 状态的区别
15 ---
const App = React.createClass({
getInitialState(){
retrun{
isEditing:false
}
},
render(){}
});
16---
class App extends React.Component{
constructor(props){
super(props);
this.state={
isEditing:false
}
}
render(){}
}
- this的区别
15---
会正确的绑定到实例上
16---
应为使用了ES6,属性并不会自动绑定到React类的实例上,方法需要bind(),或者剪头函 数绑定
- Mixins 混合的区别
16---
由于使用ES6的方式创建组件,已经不能使用
react路由 react-router-dom
<Switch></Switch>
为横向匹配
<Route path="/home" exact component={Home}></Route>
( exact ) 为纵向匹配 如果是嵌套路由则不可用
<Redirect to='/' />
路由重定向 一般配合Switch使用
<NavLink to='/home' activeClassName="selected"></NavLink>
路由切换TAB选中样式 也可activeStyle={{color:'red'}}
直接添加样式
获取DOM元素
<Child ref = 'child'/>
console.log(this.refs.child);
// 访问挂载在组件上ref
console.log(this.refs.child.refs.update);
// 访问挂载在dom元素上的ref
懒加载
React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。
注意:
React.lazy
和 Suspense 技术还不支持服务端渲染。如果你想要在使用服务端渲染的应用中使用,我们推荐 Loadable Components 这个库。它有一个很棒的服务端渲染打包指南。
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}