本文从属于 React入门与最佳实践 中的 React组件基础
前文介绍的组件的定义方式主要是声明式组件,其与传统的jQuery中以DOM操作为核心的命令式组件生成相比具有更大的灵活性与可组合性。而实际上随着应用复杂度与所需要的组件数目的持续增加,我们所需要的组件也会被划分为很多的类型。从组件组合的角度或者所谓动态组件的角度来看,常见的即是HOC模式,即将某个组件作为另一个组件的Props或者子组件从而封装出高阶组件。还有另一种偏向函数式的模式即是构造出函数式组件,就好像Arrow Function一样,对于无状态的简单组件,使用函数式组件的方式声明,会使得代码的可读性更好,并且减少冗余代码的数目。在React本身对于界面的抽象可以用 View = f(props)
,即纯粹的界面的渲染函数可以近似看做纯函数。函数式组件与基于Class声明的组件相比,其具有以下特性:
不需要声明类,可以避免大量的譬如extends或者constructor这样的代码
不需要显示声明this关键字,在ES6的类声明中往往需要将函数的this关键字绑定到当前作用域,而因为函数式声明的特性,我们不需要再强制绑定:
onClick={this.sayHi.bind(this)}>Say Hi</a> onClick={sayHi}>Say Hi</a>
贯彻最佳实践,在 React组件复用与组合 中我们会提到,应当避免在底层的展示性组件中混入对于状态的管理,而应该将状态托管于某个高阶组件或者其他的状态容器中。利用函数式声明组件可以彻底保证不会在组件中进行状态操作。
易于理解与测试
更佳的性能表现:因为函数式组件中并不需要进行生命周期的管理与状态管理,因此React并不需要进行某些特定的检查或者内存分配,从而保证了更好地性能表现。
最后,通过下图的对比,可以看出函数式组件声明方法的简洁性:
这里我们定义一个简单的Text组件:
class Text extends React.Component { render() { return <p>{this.props.children}</p>; } } React.render(<Text>Hello World</Text>, document.body);
上面定义的Text组件可以看做典型的Pure Components,或者说是Dummy Components,即好像函数式编程中的纯函数一样,输出完全由输入的Props决定,并且不会产生任何的副作用。这种类型的组件会在我们的应用中占据很大的份额,而在React 0.14之后也允许我们以类似于定义函数的方式来定义这种无状态组件,如下所示:
const Text = (props) => <p>{props.children}</p>; // ReactDOM is part of the introduction of React 0.14 ReactDOM.render( <Text>Hello World</Text>, document.querySelector('#root') );
这种模式主要是鼓励在大型项目中尽可能地以简单的写法来分割原本庞大的组件,而未来React也会面向这种无状态的组件在譬如避免无意义的检查或者内存分配领域进行一些专门的优化。这种无状态函数式组件的写法也是支持设置默认的Props类型与值的:
const Text = ({ children }) => <p>{children}</p> Text.propTypes = { children: React.PropTypes.string }; Text.defaultProps = { children: 'Hello World!' };
我们也可以利用ES6默认函数参数的方式来设置默认值:
const Text = ({ children = 'Hello World!' }) => <p>{children}</p>
另外,在无状态的组件函数中,我们也是可以访问Context的:
const Text = (props, context) => <p style={context}>props.children</p>; Text.contextTypes = { fontFamily: React.PropTypes.string }; class App extends React.Component { static childContextTypes = { fontFamily: React.PropTypes.string } getChildContext() { return { fontFamily: 'Helvetica Neue' }; } render() { return <Text>Hello World</Text>; } }