在初学 React 的时候,分不清 React 组件和 React 元素,着实踩了一些坑。搞清楚 React 中什么是组件,什么是元素,既可以理清楚概念,也可以让你避免一些不必要的错误。
React 元素
React 元素(React element),它是 React 中最小基本单位,我们可以使用 JSX 语法轻松地创建一个 React 元素:
1 | const element = <div className='element'>I'm element</div> |
React 元素不是真实的 DOM 元素,它仅仅是 js 的普通对象(plain objects),所以也没办法直接调用 DOM 原生的 API。上面的 JSX 转译后的对象大概是这样的:
1 | { |
只有在这个元素渲染被完成后,才能通过选择器的方式获取它对应的 DOM 元素。不过,按照 React 有限状态机的设计思想,应该使用状态和属性来表述组件,要尽量避免 DOM 操作,即便要进行 DOM 操作,也应该使用 React 提供的接口ref
和getDOMNode()
。一般使用 React 提供的接口就足以应付需要 DOM 操作的场景了,因此像 jQuery 强大的选择器在 React 中几乎没有用武之地了。
除了使用 JSX 语法,我们还可以使用 React.createElement()
和 React.cloneElement()
来构建 React 元素。
React.createElement()
JSX 语法就是用React.createElement()
来构建 React 元素的。它接受三个参数,第一个参数可以是一个标签名。如div
、span
,或者 React 组件。第二个参数为传入的属性。第三个以及之后的参数,皆作为组件的子组件。
1 | React.createElement( |
React.cloneElement()
React.cloneElement()
与React.createElement()
相似,不同的是它传入的第一个参数是一个 React 元素,而不是标签名或组件。新添加的属性会并入原有的属性,传入到返回的新元素中,而就的子元素奖杯替换。
1 | React.cloneElement( |
React 组件
React 中有三种构建组件的方式。React.createClass()
、ES6 class
和无状态函数。
React.createClass()
React.createClass()
是三种方式中最早,兼容性最好的方法。在0.14版本前官方指定的组件写法。
1 | var Greeting = React.createClass({ |
ES6 class
ES6 class
是目前官方推荐的使用方式,它使用了ES6标准语法来构建,但它的实现仍是调用React.createClass()
来实现了,ES6 class
的生命周期和自动绑定方式与React.createClass()
略有不同。
1 | class Greeting extends React.Component{ |
无状态函数
无状态函数是使用函数构建的无状态组件,无状态组件传入props
和context
两个参数,它没有state
,除了render()
,没有其它生命周期方法。
1 | function Greeting (props) { |
React.createClass()
和ES6 class
构建的组件的数据结构是类,无状态组件数据结构是函数,它们在 React 被视为是一样的。
元素与组件的区别
元素是一个纯的JSON对象,用于描述你想通过DOM节点或者其他组件在荧屏上展示的内容。元素可以在他们的参数里面包含其他元素。创建一个React元素代价非常小。一个元素一旦被创建,将不可更改。
一个组件可以用几种不同的方式去声明。可以是一个带有render()
方法的类。作为另外一种选择,在简单的情况下,组件可以被定义为一个函数。在两种方式下,组件都是被传入的参数作为输入内容,以返回的元素作为输出内容。
如果有一个组件被调用,传入了一些参数作为输入,那是因为有一某个父组件返回了一个带有这个组件的type
以及这些参数(到React上)。这就是为什么大家都认为参数流动方式只有一种:从父组件到子组件。
实例就是你在组件上调用this时候得到的东西,它对本地状态存储以及对响应生命周期事件非常有用。
函数组件根本没有实例,类组件拥有实例,但是你从来都不需要去直接创建一个组件实例——React会帮你管理好它。
最后,想要创建元素,使用React.createElement()
,JSX或者一个元素工厂工具。不要在实际代码上把元素写成纯JSON对象——仅需要知道他们在React机制下面以纯JSON对象存在就好。