组件可以让你将UI分割成独立的,可复用的模块,然后考虑将每个模块彼此隔离。
从概念上理解,组件就像js中的函数。他们接受随意的输入(被称为props)然后返回React元素来描述屏幕上应该出现什么。函数式和类式组件
定义一个组件最简单的方法是写一个js函数:
function Welcome(props) { returnHello, {props.name}
;}
这个函数是一个有效的React组件因为它接受一个props对象作为参数然后返回一个React元素。我们把这样的叫做函数式组件因为他们就是字面意思上js函数。
你也可以使用ES6的class来定义一个组件:
class Welcome extends React.Component { render() { returnHello, { this.props.name}
; }}
从React的角度来看,以上两种方式定义的组件是一样的。
类定义这种方法有一些额外的特性我们在下一章节会讨论。在此之前,我们会使用函数来定义组件因为这样比较简洁。
渲染一个组件
先前,我们只遇到React元素代表DOM标签的情况:
const element = ;
然而,React元素也可以代表用户自定义组件:
const element =;
当React认为一个元素代表用户自定义组件时,它通过单个对象传递JSX属性到这个组件。我们叫这个对象为“props”。
举个例子,这段代码渲染“Hello, Sara”到页面上:
function Welcome(props) { returnHello, {props.name}
;}const element =;ReactDOM.render( element, document.getElementById('root'));
。
让我们概括一下在这个例子中到底发生了什么:
- 我们调用了ReactDOM.render()来渲染<Welcome name="Sara"/>元素。
- React调用Welcome组件并将{name: 'Sara'}这个对象作为props传入。
- Welcome组件返回了一个<h1>Hello, Sara</h1>元素作为结果。
- React DOM高效地更新了DOM来匹配<h1>Hello, Sara</h1>。
附加说明:
总是将组件名的首字母大写。
举个例子,<div/>代表一个DOM标签,但是<Welcome />代表一个一个组件并且需要Welcome定义或引入。
组合组件
组件可以在它的输出中引用其他组件。这样我们可以使用同一个组件抽象出任意等级的细节。一个按钮,一个表单,一个目录,一个对话框,整个屏幕内容:在React应用中,所有这些都同样表示为组件。
举个例子,我们创建一个渲染Welcome组件多次的App组件:
function Welcome(props) { returnHello, {props.name}
;}function App() { return ();}ReactDOM.render(, document.getElementById('root'));
。
通常,新的React应用有一个单独的App组件在最顶端。然而,如果你整合React到一个已经存在的应用里,也许你会从底开始通过小组件类似Button逐渐替换一直到最高级别。
附加说明:
组件必须返回一个单个的根元素。这就是为什么我们添加了一个<div>去包含所有<Welcome />元素。
提取组件
不要害怕将组件分割成更小的组件。
举个例子,看看这个Comment组件:
function Comment(props) { return ();}{props.author.name}{props.text}{formatDate(props.date)}
。
Comment组件接受了author(一个对象),text(一个字符串)和date(一个日期对象)作为属性,它在一个社会媒体网站上描述一段评论。
这个组件可以被简化因为嵌套的东西太多,它很难被复用。让我们从这里提取出一些组件。
首先,我们将提取Avatar:
function Avatar(props) { return ( );}
Avatar组件不需要知道自己将要被渲染到Comment内部。这就是为什么我们给他的属性一个更通用的名字:user而不是author。
建议在命名属性名的时候从组件自己的角度来命名而不要从使用时的上下文环境来命名。
现在可以将Comment组件简化为更小的部分:
function Comment(props) { return ();} {props.author.name}{props.text}{formatDate(props.date)}
function UserInfo(props) { return ();} {props.user.name}
这允许我们更进一步地简化Comment:
function Comment(props) { return ();} {props.text}{formatDate(props.date)}
。
提取组件也许看起来像很枯燥的工作,但是拥有一系列可复用的组件会在大型应用中起到很好的效果。有一个很好的经验法则就是如果有一部分UI已经被使用多次(如Button,Panel,Avatar),或者组件本身已经足够复杂(如APP,FeedStory,Comment),那么使它成为一个可复用的组件会更合适。
props是只读的
如果你声明了一个组件使用函数或者类,那么它永远不能修改它自己的props。看看这个sum函数:
function sum(a, b) { return a + b;}
这样的函数被称为“纯函数”因为它们不尝试改变它们的输入,而且在输入同样的情况下一直返回一样的结果。
相比之下,这个函数就不是纯函数因为它改变了输入:
function withdraw(account, amount) { account.total -= amount;}