jsx是什么?
我们说JSX的全称应该翻译为Javscriptのxml(Javscript中的xml),而没有翻译成Javascript和xml,这是因为比起xml/html标签,这更像是在javascript中扩展了一个功能,它把xml当做变量的值赋给js变量,这是对javascript语法的延伸。
使用JSX语法后,你必须要引入babel的JSX解析器,把JSX转化成JS语法,这个工作会由babel自动完成。同时引入babel后,你就可以使用新的es6语法,babel会帮你把es6语法转化成es5语法,兼容更多的浏览器。
上面这段代码就在通过babel转换后的代码。同时可以发现每个节点都是由react.createElement编写出来的。
虚拟DOM
生命周琦
15生命周期
componentReceliveProps并不是由props的变化触发的,而是由父组件的更新触发的。
组件通信
父子组件通信
/* 子组件 */
function Son(props){
const { fatherSay , sayFather } = props
return <div className='son' >
我是子组件
<div> 父组件对我说:{ fatherSay } </div>
<input placeholder="我对父组件说" onChange={ (e)=>sayFather(e.target.value) } />
</div>
}
/* 父组件 */
function Father(){
const [ childSay , setChildSay ] = useState('')
const [ fatherSay , setFatherSay ] = useState('')
return <div className="box father" >
我是父组件
<div> 子组件对我说:{ childSay } </div>
<input placeholder="我对子组件说" onChange={ (e)=>setFatherSay(e.target.value) } />
<Son fatherSay={fatherSay} sayFather={ setChildSay } />
</div>
}
兄弟组件通信
发布(触发)订阅(监听)模式多层级通信
Context API(组件树全局通信)
即便组件的shouldComponentUpdate返回false,它仍然可以“穿透”组件继续向后代组件进行传播进而确保了数据生产者和数据消费者之间数据的一致性。
import React, { useState, useEffect } from 'react'
import './App.css'
import Title from './components/Title/indx'
export const AppContext = React.createContext('')
const App: React.FC = () => {
return (
<AppContext.Provider value={'这是一个title'}>
<div className='App'>
<Title />
<div>这是一段文字</div>
</div>
</AppContext.Provider>
)
}
export default App
import React from 'react'
import { AppContext } from '../../App'
const Title = () => {
return (
<>
<h1>title</h1>
<AppContext.Consumer>{value => <div>{value}</div>}</AppContext.Consumer>
</>
)
}
export default Title
redux通信
- Redux: 首先 Redux 是一个应用状态管理js库,它本身和 React 是没有关系的,换句话说,Redux 可以应用于其他框架构建的前端应用,甚至也可以应用于 Vue 中。
- React-Redux:React-Redux 是连接 React 应用和 Redux 状态管理的桥梁。React-redux 主要专注两件事,一是如何向 React 应用中注入 redux 中的 Store ,二是如何根据 Store 的改变,把消息派发给应用中需要状态的每一个组件
store是一个单一的数据源,而且知识只读的。
action 是对变化的描述。
/*
stroe.jsx
创建整个store
*/
import { applyMiddleware, createStore } from 'redux'
const reducer: any = (state = { number: 1 }, action: any) => {
switch (action.type) {
case 'ADD':
return { number: state.number + 1 }
case 'DEL':
return { number: state.number - 1 }
default:
return { number: state.number }
}
}
export const actions = {
ADD: () => ({ type: 'ADD' }),
DEL: () => ({ type: 'DEL' }),
}
const logMiddleware = () => {
return (next: any) => {
return (action: any) => {
const { type } = action
console.log('发生了一次action', type)
return next(action)
}
}
}
const middleware = applyMiddleware(logMiddleware)
const store = createStore(reducer, { number: 0 }, middleware)
export default store
creatStore()
const Store = createStore(rootReducer,initialState,middleware)
- 参数一 reducers : redux 的 reducer ,如果有多个那么可以调用 combineReducers 合并。
- 参数二 initialState :初始化的 state 。
- 参数三 middleware :如果有中间件,那么存放 redux 中间件。 ```jsx / 注入stroe /
import React, { useState, useEffect } from ‘react’ import ‘./App.css’ import Reducer from ‘./components/Reducer’ import store from ‘./store/stroe’ import { Provider } from ‘react-redux’
const App: React.FC = () => { return (
export default App
```jsx
/*
在组件中使用
*/
import React, { useState } from 'react'
import { connect } from 'react-redux'
import { actions } from '../../store/stroe'
const Reducer = (props: any) => {
return (
<div>
<button onClick={props.Add}>+1</button>
<button onClick={props.Del}>-1</button>
<div>{props.number}</div>
</div>
)
}
const mapStateToProps = (state: any) => ({ number: state.number })
const mapDispatchToProps = (dispatch: any) => ({
Add: () => dispatch(actions.ADD()),
Del: () => dispatch({ type: 'DEL' }),
})
export default connect(mapStateToProps, mapDispatchToProps)(Reducer)
connect 详解
connect() 接收四个参数,它们分别是 mapStateToProps,mapDispatchToProps,mergeProps和options。
mapStateToProps这个函数允许我们将 store 中的数据作为 props 绑定到组件上。
mapDispatchToProps它的功能是,将 action 作为 props 绑定到 Reducer组件上。
React-Hooks
useState
为函数组件引入状态
const [text, setText] = useState('123')
useEffect
# 挂在执行
useEffect(() => {
// 带些代码
}, [])
# text变化时执行
useEffect(() => {
return () => {}
}, [text])
useEffect(() => {
// effect
# 卸载执行
return () => {
// cleanup
}
}, [input])
虚拟DOM
本质上是JS和DOM之间的一个映射缓存在形态上表现为一个能够描述DOM结构及其属性信息的JS对象。
虚拟DOM是JS对象,他描述了一个真实的DOM。
挂载阶段
React将结合JSX的描述,构建出虚拟DOM树,然后通过ReactDOM.render实现虚拟DOM到真实DOM的映射(触发渲染流水线)。
更新阶段
页面的变化会先作用于虚拟DOM,虚拟DOM将在JS层借助算法先对比出具体有哪些真实DOM需要被改变,然后再将这些改变作用于真实DOM。
栈调和 与 Diff算法(React 15)
一个DOM节点在某一时刻最多会有4个节点和他相关。
- current Fiber。如果该DOM节点已在页面中,current Fiber代表该DOM节点对应的Fiber节点。
- workInProgress Fiber。如果该DOM节点将在本次更新中渲染到页面中,workInProgress Fiber代表该DOM节点对应的Fiber节点。
- DOM节点本身。
- JSX对象。即ClassComponent的render方法的返回结果,或FunctionComponent的调用结果。JSX对象中包含描述DOM节点的信息。
Diff算法的本质是对比1和4,生成2。
调和是“使一致”的过程——> 包括组件的挂载和卸载和更新
Diff是“找不同”的过程
若两个组件属于同一个类型,它们将拥有相同的DOM树形结构处于同一层级的一组子节点,可用通过设置key作为唯一标识从而维持各个节点在不同渲染过程中的稳定性。
Diff过程
Diff 算法性能突破的关键点在于“分层对比”。
2.类型一致的节点才有继续Diff的必要性。-
setState到底是同步还是异步的(react 15)
并不是setTimeout改变了setState而是setTimeout帮助setState“逃脱” 了React 对它的管控只要是在React管控下的setState,一定是异步的
在React钩子函数及合成事件中,它表现为异步。
在setTimeout、setInterval 等函数中包括在DOM原生事件中,它都表现为同步。