React 技术分享

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 处理数据提升性能
    原文作者:huahuadavids
    原文地址: https://segmentfault.com/a/1190000018475788
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞