HolyZheng / holyZheng-blog

草稿
36 stars 0 forks source link

react 小知识点 #53

Open HolyZheng opened 3 years ago

HolyZheng commented 3 years ago

JSX

JSX其实就是React.createElement的语法糖,不一定要使用,但是推荐使用。因为:

  1. JSX可以让我以类似 XML 的方式去开发,比起直接编写React.createElement 要更加简便且可读性更高。
  2. babel可以帮我们将JSX转成React.createElement。
  3. JSX 比起模版的方法要更加的灵活,语法、指令等概念更少。

babel如何将JSX转成React.createElement的

// babel 深度优先遍历AST,在进入节点的时候调用下面visitor
module.exports = function (babel) {
  var t = babel.types;
  return {
    name: "custom-jsx-plugin",
    visitor: {
       // 如果当前节点是jsx类型的话
      JSXElement(path) {
        // 获取到当前节点的 tagName
        var openingElement = path.node.openingElement;
        var tagName = openingElement.name.name;
        var args = []; 
        // 将tagName转为字符串并推入args数组
        args.push(t.stringLiteral(tagName)); 
        // 这里假设节点没有属性
        var attribs = t.nullLiteral(); 
        args.push(attribs); 
        var reactIdentifier = t.identifier("React"); //object
        var createElementIdentifier = t.identifier("createElement"); 
        // 构建一个表达式:React.createElement 的ast
        var callee = t.memberExpression(reactIdentifier, createElementIdentifier)
        // 构建表达式的执行 React.createElement('tagName', null) 的ast
        var callExpression = t.callExpression(callee, args); 
        // 子节点作为参数加进表达式 React.createElement('tagName', null, path.node.children) 的ast
        callExpression.arguments = callExpression.arguments.concat(path.node.children);
       // 将转换的ast 节点替换掉原来的节点
        path.replaceWith(callExpression, path.node); 
        // babel会继续往下遍历处理子节点。
      },
    },
  };