GVKun编程网logo

reactjs – 使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器

13

在本文中,您将会了解到关于reactjs–使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器的新资讯,并给出一些关于Reactjs

在本文中,您将会了解到关于reactjs – 使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器的新资讯,并给出一些关于React jsx转换与createElement使用超详细讲解、React.createClass 、React.createElement、Component、React.createElement 和 ReactDOM.render 的简易实现、React/Typescript - 需要至少 '3' 个参数,但 JSX 工厂 'React.createElement' 最多提供 '2' TS622的实用技巧。

本文目录一览:

reactjs – 使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器

reactjs – 使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器

JSX Transformer导致错误

当我使用react-tools的转换器转换我的反应文件时

$jsx public/dev/jsx public/prod/js --no-cache-dir

或者当我用grunt-react转换时

$grunt react

我的生产文件中断,因为转换使用React.createElement,并且错误表明此函数未定义.

<h1>{this.state.title}</h1>

转换为:

React.createElement("div",null,React.createElement("h1",this.state.title)

代替:

React.DOM.h1(null,this.state.title)

实时转换器工作正常,因为它使用React.DOM.h1(null,this.state.title).这行代码适用于react,但React.createElement()函数不起作用且找不到.

如何强制我的自动转换器(JSX或grunt)转换为React.DOM.h1(null)而不是React.createElement(h1,null).为什么转换器使用此功能?

我和coffee-react-transform lib有同样的错误.这些库正在针对React 0.12进行更新.如果你仍然使用React 0.11,你可能需要回滚grunt-react到稍微旧的版本,或者碰到React 0.12.

React jsx转换与createElement使用超详细讲解

React jsx转换与createElement使用超详细讲解

jsx的转换

我们从 react 应用的入口开始对源码进行分析,创建一个简单的 hello, world 应用:

import React, { Component } from ''react'';
import ReactDOM from ''react-dom'';
export default class App extends Component {
  render() {
    return <div>hello, world</div>;
  }
}
ReactDOM.render(<App />, document.getElementById(''root''));

我们注意到,我们在 App 组件中直接写了 return <div>hello, world</div> 的 jsx 语句,那么 jsx 语法是如何被浏览器识别执行的呢?

另外我在第一次学习 react 的时候,就有一个疑惑: import React, { Component } from ''react'' 这段代码中,React 似乎在代码中没有任何地方被用到,为什么要引入呢?

16.x版本及之前

我们在 react16.8 版本的代码中,尝试将 React 的引用去掉:

// import React, { Component } from ''react'';
import { Component } from ''react''; // 去掉 React 的引用
import ReactDOM from ''react-dom'';
export default class App extends Component {
  render() {
    return <div>hello, world</div>;
  }
}
ReactDOM.render(<App />, document.getElementById(''root''));

运行应用程序,发现会提示 ''React'' must be in scope when using JSX 的 error:

这是因为上述的类组件 render 中返回了 <div>hello, world</div> 的 jsx 语法,在React16版本及之前,应用程序通过 @babel/preset-react 将 jsx 语法转换为 React.createElement 的 js 代码,因此需要显式将 React 引入,才能正常调用 createElement。我们可以在 Babel REPL 中看到 jsx 被 @babel/preset-react 编译后的结果

17.x版本及之后

React17版本之后,官方与 bbel 进行了合作,直接通过将 react/jsx-runtime 对 jsx 语法进行了新的转换而不依赖 React.createElement,转换的结果便是可直接供 ReactDOM.render 使用的 ReactElement 对象。因此如果在React17版本后只是用 jsx 语法不使用其他的 react 提供的api,可以不引入 React,应用程序依然能够正常运行。

更多有关于 React jsx 转换的内容可以去看官网了解:介绍全新的JSX转换,在这里就不再过多展开了。

React.createElement源码

虽然现在 react17 之后我们可以不再依赖 React.createElement 这个 api 了,但是实际场景中以及很多开源包中可能会有很多通过 React.createElement 手动创建元素的场景,所以还是推荐学习一下React.createElement源码。

React.createElement 其接收三个或以上参数:

  • type:要创建的 React 元素类型,可以是标签名称字符串,如 ''div'' 或者 ''span'' 等;也可以是 React组件 类型(class组件或者函数组件);或者是 React fragment 类型。
  • config:写在标签上的属性的集合,js 对象格式,若标签上未添加任何属性则为 null。
  • children:从第三个参数开始后的参数为当前创建的React元素的子节点,每个参数的类型,若是当前元素节点的 textContent 则为字符串类型;否则为新的 React.createElement 创建的元素。

函数中会对参数进行一系列的解析,源码如下,对源码相关的理解都用注释进行了标记:

export function createElement(type, config, children) {
  let propName;
  // 记录标签上的属性集合
  const props = {};
  let key = null;
  let ref = null;
  let self = null;
  let source = null;
  // config 不为 null 时,说明标签上有属性,将属性添加到 props 中
  // 其中,key 和 ref 为 react 提供的特殊属性,不加入到 props 中,而是用 key 和 ref 单独记录
  if (config != null) {
    if (hasValidRef(config)) {
      // 有合法的 ref 时,则给 ref 赋值
      ref = config.ref;
      if (__DEV__) {
        warnIfStringRefCannotBeAutoConverted(config);
      }
    }
    if (hasValidKey(config)) {
      // 有合法的 key 时,则给 key 赋值
      key = '''' + config.key;
    }
    // self 和 source 是开发环境下对代码在编译器中位置等信息进行记录,用于开发环境下调试
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // 将 config 中除 key、ref、__self、__source 之外的属性添加到 props 中
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }
  // 将子节点添加到 props 的 children 属性上
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    // 共 3 个参数时表示只有一个子节点,直接将子节点赋值给 props 的 children 属性
    props.children = children;
  } else if (childrenLength > 1) {
    // 3 个以上参数时表示有多个子节点,将子节点 push 到一个数组中然后将数组赋值给 props 的 children
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    // 开发环境下冻结 childArray,防止被随意修改
    if (__DEV__) {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }
  // 如果有 defaultProps,对其遍历并且将用户在标签上未对其手动设置属性添加进 props 中
  // 此处针对 class 组件类型
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  // key 和 ref 不挂载到 props 上
  // 开发环境下若想通过 props.key 或者 props.ref 获取则 warning
  if (__DEV__) {
    if (key || ref) {
      const displayName =
        typeof type === ''function''
          ? type.displayName || type.name || ''Unknown''
          : type;
      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }
      if (ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }
  // 调用 ReactElement 并返回
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

相关参考视频:传送门

由代码可知,React.createElement 做的事情主要有:

  • 解析 config 参数中是否有合法的 key、ref、__source 和 __self 属性,若存在分别赋值给 key、ref、source 和 self;将剩余的属性解析挂载到 props 上
  • 除 type 和 config 外后面的参数,挂载到 props.children
  • 针对类组件,如果 type.defaultProps 存在,遍历 type.defaultProps 的属性,如果 props 不存在该属性,则添加到 props 上
  • 将 type、key、ref、self、props 等信息,调用 ReactElement 函数创建虚拟 dom,ReactElement 主要是在开发环境下通过 Object.defineProperty 将 _store、_self、_source 设置为不可枚举,提高 element 比较时的性能:
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // 用于表示是否为 ReactElement
    $$typeof: REACT_ELEMENT_TYPE,
    // 用于创建真实 dom 的相关信息
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
  };
  if (__DEV__) {
    element._store = {};
    // 开发环境下将 _store、_self、_source 设置为不可枚举,提高 element 的比较性能
    Object.defineProperty(element._store, ''validated'', {
      configurable: false,
      enumerable: false,
      writable: true,
      value: false,
    });
    Object.defineProperty(element, ''_self'', {
      configurable: false,
      enumerable: false,
      writable: false,
      value: self,
    });
    Object.defineProperty(element, ''_source'', {
      configurable: false,
      enumerable: false,
      writable: false,
      value: source,
    });
    // 冻结 element 和 props,防止被手动修改
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }
  return element;
};

所以通过流程图总结一下 createElement 所做的事情如下:

React.Component 源码

我们回到上述 hello,world 应用程序代码中,创建类组件时,我们继承了从 react 库中引入的 Component,我们再看一下React.Component源码:

function Component(props, context, updater) {
  // 接收 props,context,updater 进行初始化,挂载到 this 上
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // updater 上挂载了 isMounted、enqueueForceUpdate、enqueueSetState 等触发器方法
  this.updater = updater || ReactNoopUpdateQueue;
}
// 原型链上挂载 isReactComponent,在 ReactDOM.render 时用于和函数组件做区分
Component.prototype.isReactComponent = {};
// 给类组件添加 `this.setState` 方法
Component.prototype.setState = function(partialState, callback) {
  // 验证参数是否合法
  invariant(
    typeof partialState === ''object'' ||
      typeof partialState === ''function'' ||
      partialState == null
  );
  // 添加至 enqueueSetState 队列
  this.updater.enqueueSetState(this, partialState, callback, ''setState'');
};
// 给类组件添加 `this.forceUpdate` 方法
Component.prototype.forceUpdate = function(callback) {
  // 添加至 enqueueForceUpdate 队列
  this.updater.enqueueForceUpdate(this, callback, ''forceUpdate'');
};

从源码上可以得知,React.Component 主要做了以下几件事情:

  • 将 props, context, updater 挂载到 this 上
  • 在 Component 原型链上添加 isReactComponent 对象,用于标记类组件
  • 在 Component 原型链上添加 setState 方法
  • 在 Component 原型链上添加 forceUpdate 方法,这样我们就理解了 react 类组件的 super() 作用,以及 this.setStatethis.forceUpdate 的由来

总结

本章讲述了 jsx 在 react17 之前和之后的不同的转换,实际上 react17 之后 babel 的对 jsx 的转换就是比之前多了一步 React.createElement 的动作:

另外讲述了 React.createElementReact.Component 的内部实现是怎样的。通过 babel及 React.createElement,将 jsx 转换为了浏览器能够识别的原生 js 语法,为 react 后续对状态改变、事件响应以及页面更新等奠定了基础。

后面的章节中,将探究 react 是如何一步步将状态等信息渲染为真实页面的。

到此这篇关于React jsx转换与createElement使用超详细讲解的文章就介绍到这了,更多相关React jsx转换与createElement内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • react源码层深入刨析babel解析jsx实现
  • React详细讲解JSX和组件的使用
  • react中JSX的注意点详解
  • React学习之JSX与react事件实例分析
  • React前端开发createElement源码解读
  • React createElement方法使用原理分析介绍
  • React的createElement和render手写实现示例

React.createClass 、React.createElement、Component

React.createClass 、React.createElement、Component

react里面有几个需要区别开的函数

React.createClass 、React.createElement、Component

首选看一下在浏览器的下面写法:

<div id="app">
    </div>
    <script src="../js/react.js"></script>
    <script src="../js/react-dom.js"></script>
    <script src="../js/browser.min.js"></script>
    <script type="text/babel">
     var  Info = React.createClass({  //创建一个react模板
					      render:function(){
					        return <p>createClass----{this.props.you}</p>
					      }
					});
    var eleC = React.createClass({ //创建一个react模板
			      	render:function(){
			        return <div>createElement---{this.props.name}</div>
			    	}
    });
    
    var eleProps = {name:"eleC"};
    var ele = React.createElement(eleC,eleProps); //创建一个react元素;第一个参数为模板,第二个参数为模板的props	
    
    //ReactDOM.render是React的最基本方法用于将模板转为HTML语言,并插入指定的DOM节点。ReactDOM.render(template,targetDOM),该方法接收两个参数:第一个是创建的模板,多个dom元素外层需使用一个标签进行包裹
    ReactDOM.render(
      <div>
        <Info  you="createClass" />
        {ele} 
      </div>,
      document.getElementById(''app'')
    );
		
    </script>

  

React.createClass  是创建了一个react模板,使用的时候,像html标签一样,比如上面的info

React.createElement 是创建了一个react元素,相当于把模板具体化,使用的时候,是当做js变量,直接写入,比如上面的 {ele}

 

以上是在浏览器引入的写法,下面看看,用npm构建的写法

import React, { Component } from ''react'';
import ReactDOM from ''react-dom'';

class App extends Component {
 
  render() {
    return (
      <div className="App">
        这里是app
      </div>
    );
  }
}

class Info extends Comment{
    render(){
        return (
            <div>
                info
            </div>
        )
    }
}

class Ele extends Comment{
    render(){
        return (
            <div>
                ele
            </div>
        )
    }
}
var myProps ={

};
var ele = React.createElement(Ele,myProps);



ReactDOM.render(<App>
    <Info></Info>
    {ele}
</App>,document.getElementById(''root''));

  

区别在于,使用服务启动,不再需要用 React.createClass 来创建模块,直接使用类,来继承 Component 类即可完成模板创建。。后面使用的方式基本一致。要注意的是内部 初始化 state和props等有区别 

 

React.createElement 和 ReactDOM.render 的简易实现

React.createElement 和 ReactDOM.render 的简易实现

前言

React.createElement 是React中一种创建React组件的方式,它古老而神秘。

虽然日常开发中已经很少能够见到他的身影。但是将JSX用babel编译之后,就是 createElement 函数

ReactDOM.render 是React实例渲染到dom的入口方法

React.createElement

参数

createElement 支持传入n个参数。

  • type:表示你要渲染的元素类型。这里可以传入一个元素Tag名称,也可以传入一个组件(如div span ul li 等,也可以是是函数组件和类组件)
  • config:创建React元素所需要的props。包含 style,className 等
  • children:要渲染元素的子元素,这里可以向后传入n个参数。参数类型皆为 React.createElement 返回的React元素对象。
React.createElement(type, config, children1, children2, children3...);
复制代码

createElement 方法

我们新建一个JS文件,导出一个 createElement 函数。

方法内置一个props变量。将我们的config对象本身所有的属性完全copy到 props

function createElement(type, config, children) {
    const props = {};

    for (let propName in config) {
        // 如果对象本身存在该属性值,就copy
        if (Object.prototype.hasOwnProperty.call(config, propName)) {
            props[propName] = config[propName];
        }
    }
}

export default {
    createElement,
}
复制代码

接着开始处理子元素。由于子元素的参数位置在 第2个 及其之后,所以我们需要用到函数的 arguments 对象获取参数值。

在 createElement 中声明一个 childrenLength 变量,值为 arguments.length - 2

  • 如果 childrenLength === 1,也就是子元素只有1个,就将唯一的子元素挂到props.children上面。
  • 如果 childrenLength > 1,那就从第二个参数向后截取 arguments 对象。

这里可以使用 Array.prototype.slice.call 进行截取,当然也可以使用 React 的官方写法。如下方代码注释:

    // 获得子元素长度
    const childrenLength = arguments.length - 2;
    if (childrenLength === 1) {
        props.children = children;
    } else if (childrenLength > 1) {

        // 1. React 官方实现,声明一个和 childrenLength 一样长的数组
        // 然后遍历 arguments对象,把第二个之后的参数项逐个赋值给 childrenArray
        let childrenArray = Array(childrenLength);
        for (let i = 0; i < arguments.length; i++) {
            childrenArray[i] = arguments[i + 2]
        }
        props.children = childrenArray;

        // 2. 数组slice截取,截取第二个之后所有的参数项给props.children
        props.children = Array.prototype.slice.call(arguments, 2);
    }
复制代码

最后,我们返回 ReactElement(type, props) 工厂函数,React元素对象创建完成。

ReactElement 方法

ReactElement 方法是一个工厂函数,可以包装一个React虚拟Dom对象。

这里实现也很简单,只需要返回一个对象即可:

function ReactElement(type, props) {
    return {
        $$typeof: REACT_ELEMENT_TYPE,
        type,
        props
    }
}
复制代码

$$typeof: REACT_ELEMENT_TYPE

$$typeof: REACT_ELEMENT_TYPE 是React元素对象的标识属性

REACT_ELEMENT_TYPE 的值是一个Symbol类型,代表了一个独一无二的值。如果浏览器不支持 Symbol类型,值就是一个二进制值。

为什么是 Symbol?主要防止XSS攻击伪造一个假的React组件。因为JSON中是不会存在Symbol类型的。

为什么是 0xeac7 ?因为 0xeac7 和单词 React 长得很像。

const hasSymbol = typeof Symbol === ''function'' && Symbol.for;
const REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for(''react.element'') : 0xeac7;
复制代码

这样我们的 React.createElement 方法就实现了。

使用示例

import React from ''./react'';
import ReactDOM from ''react-dom'';

let apple = React.createElement(''li'', { id: ''apple'' }, ''apple'');
let banana = React.createElement(''li'', { id: ''banana'' }, ''banana'');

let list = React.createElement(''ul'', {id: ''list''}, apple, banana);

ReactDOM.render(list, document.getElementById(''root''));
复制代码

完整实现

class Component {
    static isReactComponent = true;
    constructor(props) {
        this.props = props
    }
}

const hasSymbol = typeof Symbol === ''function'' && Symbol.for; // 浏览器是否支持 Symbol
// 支持Symbol的话,就创建一个Symbol类型的标识,否则就以二进制 0xeac7代替。
// 为什么是 Symbol?主要防止xss攻击伪造一个fake的react组件。因为json中是不会存在symbol的.
// 为什么是 二进制 0xeac7 ?因为 0xeac7 和单词 React长得很像。
const REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for(''react.element'') : 0xeac7;

function ReactElement(type, props) {
    return {
        $$typeof: REACT_ELEMENT_TYPE,
        type,
        props
    }
}

function createElement(type, config, children) {
    const props = {};

    for (let propName in config) {
        // 如果对象本身存在该属性值,就copy
        if (Object.prototype.hasOwnProperty.call(config, propName)) {
            props[propName] = config[propName];
        }
    }

    const childrenLength = arguments.length - 2;

    if (childrenLength === 1) {
        props.children = children;
    } else if (childrenLength > 1) {

        // 1. React 官方实现,声明一个和childrenLength一样长的数组
        // 然后遍历 arguments对象,把第二个之后的参数项给 childrenArray
        // let childrenArray = Array(childrenLength);
        // for (let i = 0; i < arguments.length; i++) {
        //     childrenArray[i] = arguments[i + 2]
        // }
        // props.children = childrenArray;

        // 2. 数组slice截取,截取第二个之后所有的参数项给props.children
        props.children = Array.prototype.slice.call(arguments, 2);
    }
    return ReactElement(type, props)
}

export default {
    createElement,
    Component
}
复制代码

官方源码

Github地址

ReactDOM.render

参数

render 支持传入2个参数。

  • node:React组件
  • mountNode:要挂载的DOM对象
ReactDOM.render(node, mountNode);
复制代码

render 方法

新建一个JS文件,导出一个 render 函数。

先判断,如果传入的组件是一个字符串,直接使用 document.createTextNode方法创建一个文本节点,拼接在要挂载的DOM元素里面。

新开辟 typeprops 两个变量,将组件元素内的 typeprops赋值上去

function render(node, mountNode) {
    if (typeof node === ''string'') { // 如果是字符串
        return mountNode.append(document.createTextNode(node))
    }
    let type = node.type;
    let props = node.props;
}

export default {
    render
}
复制代码

接着,使用 type 创建一个相应的DOM元素节点,遍历 props 中的属性。

属性名为 children,判断 children 是不是一个数组。如果不是的话,将其包装为一个数组。如果是的话,遍历子元素,并递归调用 render 函数

如果是style,代表是行内样式。将style内的css对象,逐个复制到domElement.style上面

    let domElement = document.createElement(type);
    
    for (let propName in props) {
        if (propName === ''children'') {
            let children = props[propName];
            children = Array.isArray(children) ? children : [children];
            children.forEach(child => render(child, domElement))
        } else if (propName === ''style'') {
            let styleObj = props[propName];
            for (let attr in styleObj) {
                domElement.style[attr] = styleObj[attr];
            }
        }
    }
复制代码

最后,调用 mountNode.appendChild 方法,将处理好的元素挂载到dom元素上

mountNode.appendChild(domElement);
复制代码

函数组件的处理

我们可以判断 type 的值是否为function。如果是function,执行函数。将执行后的返回值上的 props type属性赋值给 propstype 变量

    let type = node.type;
    let props = node.props;
    
    if (typeof type === ''function'') {
        let element = type(props); // 执行函数
        props = element.props;
        type = element.type;
    }
    
    let domElement = document.createElement(type);
复制代码

类组件的处理

我们新建一个 Componet 类,模拟 React.Component 类的实现

Componet 类中有一个 isReactComponent 的静态属性,代表该类为一个React类组件。

class Component {
    // 是否为React组件
    static isReactComponent = true;
    constructor(props) {
        this.props = props
    }
}
复制代码

我们可以判断 type 上的 isReactComponent 是否为true。如果为true,代表该元素为一个 类组件。

先使用new实例化类组件,然后调用render方法获取到React元素对象。

    let type = node.type;
    let props = node.props;
    
    // 是否为类组件
    if (type.isReactComponent) {
        //传入props,并实例化,调用render方法
        let element = new type(props).render(); 
        props = element.props;
        type = element.type;
    }
复制代码

使用示例

React.createElement

let apple = React.createElement(''li'', { id: ''apple'' }, ''apple'');
let banana = React.createElement(''li'', { id: ''banana'' }, ''banana'');
let list = React.createElement(''ul'', {id: ''list''}, apple, banana);

ReactDOM.render(list, document.getElementById(''root''));
复制代码

函数组件

function list(props) {
    return (
        <ul>
            <li style={{color: props.color}}>banana</li>
            <li style={{color: props.color}}>apple</li>
        </ul>
    )
}

ReactDOM.render(
    React.createElement(List, {
        color: ''red''
    }),
    document.getElementById(''root'')
);
复制代码

类组件

class List extends React.Component {
    render() {
        return (
            <ul>
                <Item name={''banana''}/>
                <Item name={''Apple''}/>
            </ul>
        );
    }
}

class Item extends React.Component {
    render() {
        return (
            <li>{this.props.name}</li>
        )
    }
}
ReactDOM.render(React.createElement(List), document.getElementById(''root''));
复制代码

完整实现

function render(node, mountNode) {
    if (typeof node === ''string'') {
        return mountNode.append(document.createTextNode(node))
    }
    let type = node.type;
    let props = node.props;
    if (type.isReactComponent) {
        let element = new type(props).render();
        props = element.props;
        type = element.type;
    } else if (typeof type === ''function'') {
        let element = type(props);
        props = element.props;
        type = element.type;
    }
    let domElement = document.createElement(type);
    for (let propName in props) {
        if (propName === ''children'') {
            let children = props[propName];
            children = Array.isArray(children) ? children : [children];
            children.forEach(child => render(child, domElement))
        } else if (propName === ''style'') {
            let styleObj = props[propName];
            for (let attr in styleObj) {
                domElement.style[attr] = styleObj[attr];
            }
        }
    }
    mountNode.appendChild(domElement);
}

export default {
    render
}
复制代码

React/Typescript - 需要至少 '3' 个参数,但 JSX 工厂 'React.createElement' 最多提供 '2' TS622

React/Typescript - 需要至少 '3' 个参数,但 JSX 工厂 'React.createElement' 最多提供 '2' TS622

如何解决React/Typescript - 需要至少 ''3'' 个参数,但 JSX 工厂 ''React.createElement'' 最多提供 ''2'' TS622?

我有这个组件:

const TheBarTitle = (
    theClass: any,columnTitle: string,onClickAction: any,) => {
    return (
        <div
            className={theClass}
            title="Click to add this filter"
            onClick={onClickAction}
        >
            {columnTitle}
        </div>
    );
};

以这种方式使用:

 render: (rowData): any => {
                                return (
                                    <div className={classes.contentxyz}>
                                        .........                                    </div>
                                );
                            },},{
                            title: (
                                <TheBarTitle
                                    theClass={classes.contentxyz}
                                    columnTitle="THIS IS THE TITLE"
                                    onClickAction={(e: any) =>
                                        this.handletooltip(
                                            e,''theeetitle:'',)
                                    }
                                />
                            ),....

但是我收到错误:Tag ''TheBarTitle'' expects at least ''3'' arguments,but the JSX factory ''React.createElement'' provides at most ''2''. TS622

我实际上使用了 3 个参数。知道我做错了什么,它只看到 2 个吗?

解决方法

您将函数调用与组件创建方法混合在一起。 将 TheBarTitle 更改为 FunctionComponent 创建方法

interface Props {
  theClass: any
  columnTitle: string
  onClickAction: any
}
const TheBarTitle: React.FC<Props> = ({theClass,columnTitle,onClickAction}) => {
  return (
    <div
      className={theClass}
      title="Click to add this filter"
      onClick={onClickAction}
    >
      {columnTitle}
    </div>
  )
}

或者你调用这个函数:

title: TheBarTitle(classes.contentxyz,"THIS IS THE TITLE",(e: any) =>
    this.handleTooltip(e,''theeetitle:'')
    ))

对于后者,我建议也更改命名的大小写。

,

对上述问题的补充回答:

const TheBarTitle = (
    theClass: any,columnTitle: string,onClickAction: any,) => {
    return ( ... );
};

对于组件:括号之间是我们提供给函数的参数,而 React 只需要 2 个可能的值(对象)==> 因此没有像上面引用的参数那样的值)

  • 道具:成为一个对象
  • 儿童?:成为非强制性对象

你想要做的是使用:

  • react 提供的道具参数,以便使用点符号访问道具,
  • 要么解构直接访问你的道具(==>括号之间有花括号,你可以在其中访问道具)

应该是:


interface Props {
  theClass: any
  columnTitle: string
  onClickAction: any
}

// Regular 
const TheBarTitle = ( props: Props ) => {
  const { ... } = props // or props.[YOUR PROPS] to access your named props
  return ( ... );
};

// Destructuring version 
const TheBarTitle = ({
    theClass,onClickAction,} : Props ) => { return ( ... ); };

我们今天的关于reactjs – 使用React.createElement(“h1”,null)而不是React.DOM.h1(null)的JSX转换器的分享就到这里,谢谢您的阅读,如果想了解更多关于React jsx转换与createElement使用超详细讲解、React.createClass 、React.createElement、Component、React.createElement 和 ReactDOM.render 的简易实现、React/Typescript - 需要至少 '3' 个参数,但 JSX 工厂 'React.createElement' 最多提供 '2' TS622的相关信息,可以在本站进行搜索。

本文标签: