React 笔录(渲染原理和react-redux的connect简单实现)

1. createElement,render方法的简易手写

\

index.js 要实现的功能:

import React, { Component } from "./mReact";
import ReactDOM from "./mReact-dom";

function Comp(props) {
  return <h2>{props.name}</h2>;
}
const arrList = ["张三", "李四"];
class ClassComp extends Component {
  render() {
    return (
      <div>
        <p>{this.props.name}</p>
        <p>
          <span onClick={() => alert("点击了")} style={{ color: "red" }}>
            内部文字
          </span>
        </p>
        <ul>
          {arrList.map(name => (
            <li key={name}>{name}</li>
          ))}
        </ul>
      </div>
    );
  }
}

const jsx = (
  <div id="demo">
    <h1>Hello</h1>
    <Comp name="函数组件" />
    <ClassComp name="class组件" />
  </div>
);

ReactDOM.render(jsx, document.getElementById("root"));

mReact.js:  简单实现 createElement方法

import { createVNode } from "./mvdom";

// React createElement方法
function createElement(type, props, ...children) {
  props.children = children;
  delete props.__source;
  delete props.__self;
  let vType; //用于指定类型,是原生标签,还是class组件还是函数组件
  if (typeof type === "string") {
    vType = 1;
  } else if (typeof type === "function") {
    vType = type.isClassComponent ? 2 : 3;//Component指定的静态属性isClassComponent,用于判断类型
  }
  return createVNode(vType, type, props); //返回虚拟dom的一部分属性,不是全部,主要是props
}

export default { createElement };

//只做简单处理
export class Component {
  static isClassComponent = true; //判断是函数还是class

  constructor(props) {
    this.props = props;
    this.state = {};
  }
}

mReact-dom.js:  简单实现render方法,渲染dom

import { initNode } from "./mvdom";

// render方法 ReactDOM  将虚拟dom变成真实dom
function render(vnode, container) {
  let node = initNode(vnode);
  container.appendChild(node); //加到容器里面
}

export default { render };

mvdom.js:

//做个转化,返回json
export const createVNode = (vType, type, props) => {
  return { vType, type, props };
};

// 转化虚拟dom为真实dom
export function initNode(vnode) {
  const { vType } = vnode;
  //为文本,不做处理,直接返回文本节点
  if (!vType) {
    return document.createTextNode(vnode);
  }
  if (vType === 1) {
    return createNativeElement(vnode); //原生标签
  } else if (vType === 2) {
    return createClassElement(vnode); //class组件
  } else if (vType === 3) {
    return createFuncElement(vnode); //函数组件
  }
}

//原生标签处理
function createNativeElement(vnode) {
  const { props, type } = vnode;

  let node = document.createElement(type); //创建元素,type就是div,span这种

  const { children, key, ...rest } = props; //去除不是原生属性的

  Object.keys(rest).forEach(attr => {
    //特殊的进行处理
    if (attr === "className") {
      node.setAttribute("class", rest[attr]);

      //特殊的进行处理
    } else if (attr === "htmlFor") {
      node.setAttribute("for", rest[attr]);

      //style是Object进行处理,这里只是简单处理
    } else if (attr === "style" && typeof rest[attr] === "object") {
      let attrs = Object.keys(rest[attr])
        .map(a => `${a}:${rest[attr][a]}`)
        .join(";");
      node.setAttribute(attr, attrs);

      //事件处理
    } else if (attr.startsWith("on")) {
      node[attr.toLowerCase()] = rest[attr];

      //其余属性的处理
    } else {
      node.setAttribute(attr, rest[attr]);
    }
  });

  // children的里面的,进行递归处理
  if (children && children.length > 0) {
    children.forEach(chd => {
      if (Array.isArray(chd)) {
        //如果是数组,先进行拆分
        chd.length > 0 &&
          chd.forEach(element => {
            node.appendChild(initNode(element)); //转化为真实dom,加到父节点里面
          });
      } else {
        node.appendChild(initNode(chd)); //转化为真实dom,加到父节点里面
      }
    });
  }

  return node;
}

// class组件转化为真实dom
function createClassElement(vnode) {
  const { type, props } = vnode;
  let node = new type(props).render(); //class的render返回
  return initNode(node); //最后都会回归到原生标签
}

// 函数组件转化为真实dom
function createFuncElement(vnode) {
  const { type, props } = vnode;
  let node = type(props); //函数直接执行即可
  return initNode(node); //最后都会回归到原生标签
}

2. node-sass的安装 yarn配置

yarn config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/ -g

3. react-redux的connect的原理

import React, { Component } from "react";
import { MyContext } from "./context";

function connect(mapStateToProps, mapDispatchToProps) {
  return function EnhanceHoc(WrappedComponent) {
    class EnhanceComponent extends Component {
      constructor(props, context) {
        super(props);
        this.state = {
          storeState: mapStateToProps(context.getState()),  //获取mapStateToProps要更新的state
        };
      }
      componentDidMount() {
        // 监听state的变化
        this.subscribe = this.context.subscribe(() => {
          //更新state触发页面的重新render
          this.setState({
            storeState: mapStateToProps(this.context.getState()),
          });
        });
      }
      componentWillUnmount() {
        this.subscribe();
      }
      render() {
        return (
          <WrappedComponent
            {...mapStateToProps(this.context.getState())}
            {...mapDispatchToProps(this.context.dispatch)}
          ></WrappedComponent>
        );
      }
    }
    EnhanceComponent.contextType = MyContext;  //获取context
    return EnhanceComponent;
  };
}

export { connect };

4. 上面 context.js的实现

import { createContext } from "react";

const MyContext = createContext();

export { MyContext };

5.上面的MyContext的使用方式

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { MyContext } from  "./store/context";
// import { Provider} from "react-redux";
import store from "./store";

ReactDOM.render(
    <MyContext.Provider value={store}>
      <App />
    </MyContext.Provider>,
  document.getElementById('root')
);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值