1. react 介绍 和 想法
- A declarative, efficient, and flexible JavaScript library for building user interfaces
- react是一个专注于UI的库
- 状态机 输入 => 组件 => 输出
- 组件化 react组件映射 为原生android组件 原生ios 组件 react vr
2. jsx 语法
JSX就是Javascript和XML结合的一种格式,要使用需要在babelrc里配置, Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用
// 最外层必须有一个元素包裹
<div>hello world!</div>
// 属性都要驼峰
<div className="haha" ></div>
// 样式
<div style={{ marginTop: '10px'}}></div>
// 变量
<div> {user.name }</div>
// 事件
<button onClick={}> click me </button>
// 遍历
<ul>
{
list.map(
({name, value}) => <li key={name} value={value}>{name}</li>
)
}
</ul>
// 展开对象
const props = {name: "tom" }
<div {...props}></div>
3 虚拟DOM 和 diff 算法
a. 虚拟DOM(Virtual DOM)机制:对于每一个组件,React会在内存中构建一个相对应的DOM树,基于React开发时所有的DOM构造都是通过虚拟DOM进行,每当组件的状态发生变化时,React都会重新构建整个DOM数据,然后将当前的整个DOM树和上一次的DOM树进行对比,得出DOM结构变化的部分(Patchs),然后将这些Patchs 再更新到真实DOM中
b. 两个不同类型的元素会产生不同的树(根元素不同结构树一定不同)
c. 开发者可以通过key属性指定不同树中没有发生改变的子元素
d. diff算法的核心就是同级比较
4. state 和 props
- react 数据是单向流动的 数据自顶向下流动 ,
- props是传递来的参数,从父级组件向子组件传递的数据, 是只读的
- state是自己的内部状态
- 在react更新生命周期setState会导致死循环
// 默认参数
Main.defaultProps = {
list: [ ]
}
// setState 是异步的
this.setState( (prevState,props) => ({
text: prev.text + "-ha"
}))
5. 生命周期
Note: 父子组件的挂载顺序,更新顺序
6 函数式编程
- 函数式编程,函数作为一等公民,而不是类和对象
- 纯函数 一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数
- 高阶函数 函数的参数可以是函数,返回值也可以是函数 , 如数组的
forEach map filter some reduce ,setTimeout setInterval等
- 柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数
6 无状态组件
顾名思义,它没有state,接收props,它是一种只负责展示的纯组件 使用函数式的方式声明,会使得代码的可读性更好,并能大大减少代码量,多写无状态组件
function HelloComponent(props) {
return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="marlon" />, mountNode)
7 使用 fragment 碎片
Jsx 要求返回的元素,必须有东西包裹,使用碎片可以减少一层DOM
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
// 可以简写为
<>
<td>Hello</td>
<td>World</td>
</>
8 使用context
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性,React.createContext 创建一个context,一个context包含provider(数据提供者), comsumer(数据消费者), Provider 有一个value参数,用来覆盖创建时的默认值
// 创建一个 theme Context, 默认 theme 的值为 light
const ThemeContext = React.createContext ('light');
function ThemedButton(props) {
// ThemedButton 组件从 context 接收 theme
return (
<ThemeContext.Consumer>
{theme => <Button {...props} theme={theme} />}
</ThemeContext.Consumer>
);
}
// 中间组件
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
9. mobx
推荐一个react模块的目录结构
/states 状态
/(widgets|components)各类组件、弹窗等
index.js
index.less
service 建议放在config里,全局统一
Computed用于生成计算数据,autorun类似用来监听某一数据改变而作出反映
import {action, observable ,autorun} from 'mobx';
import StateAdd from "./add"
class State {
constructor(){
this.$add = new StateAdd(this);
}
// 显示
@observable show = false;
// query
@observable query = {
trade: null,
type: 1
}
/**
* @name 获取列表
*/
@action getList = () => {
}
}
const instance = new State();
autorun(() => {
if(instance.show){
console.log("打开弹窗了")
}
})
export default instance
10 高阶组件
主要有两种实现方式属性proxy、继承实现
通常使用装饰器模式调用,常见的有mobx的 @observer, react-router的withRouter等
------ 属性proxy 实现如下
import React from "react"
export default class extends React.Component {
render = () =>
<div>
<div>
<Hoc1_text name={'Hoc1_text'}/>
</div>
<div>
<Hoc2_text />
</div>
</div>
}
class Text1 extends React.Component {
render = () =>
<div>
this is simple text <br/>
{this.props.name}
</div>
}
/**
* @name 操作props
*/
function Hoc1(Component){
return class extends React.Component {
render = () =>
<div className='hoc1'>
<Component {...Object.assign({} , this.props, {gen : '111'})}/>
</div>
}
}
const Hoc1_text = Hoc1(Text1);
class Text2 extends React.Component {
render = () =>
<div>
<input type="text" value={this.props.value} onChange={this.props.change}/>
</div>
}
/**
*@name 抽离state
*/
function Hoc2(Component){
return class extends React.Component {
state = {
value: '11'
}
change = e => {
this.setState({
value: e.target.value
})
}
render = () =>
<div>
<Component value={this.state.value} change={this.change}/>
</div>
}
}
const Hoc2_text = Hoc2(Text2);
function Hoc3(Component){
return class extends React.Component {
getRef = _ref => {
this.refs = _ref;
}
render = () =>
<div>
<Component ref={this.getRef}/>
</div>
}
}
------ 继承组件 实现如下 -------
class Text extends React.Component {
render(){
return (
<div>
this is text
</div>
)
}
}
// 生命周期可以覆盖掉
const hoc2 = Component => {
return class NewHoc extends Component {
static displayName = `NewHoc-${Component.displayName || Component.name}`
render(){
const element= super.render();
console.log(element)
const style = {
color: element.type === 'div' ? 'red' : 'green'
}
const newProps = {...this.props, style}
return React.cloneElement(element, newProps, element.props.children)
}
}
}
const NewCom = hoc2(Text)
11 注意事项
- React组件名字大写
- 不能直接修改state props
- 更新函数里不能做状态操作(死循环)
- 多用无状态组件
- 多用pureComponent React.PureComponent 通过prop和state的浅对比来实现 shouldComponentUpate()。
- 代码清晰,一目了然,注释写好
- 过度封装不如不封装
- 使用 ImmutableJS 处理数据提升性能