组件化开发是 React 的核心, 学会如何利用和组织他们有助于你创建良好的设计结构.
什么是组件?
根据 react 官网的解释大致如下:
组件可以独立的拆分你的 UI 试图, 他们是可以复用的, 独立的单元.
和函数类似, React 中组件接收的输入源称为 props, 并且返回 react 元素. react 元素是对 UI 界面的描述. 你可以告诉 react 你期望的 UI 界面, 剩下的工作可以交给 react 来处理.
我们拿乘坐计程车打比方, 当你告诉司机你想要去的地方, 司机就会按照你期望地点将你安全的送到目的地. 而不用你自己亲自开车.
Component Api's
react 的 api 有哪些呢? react 总共有主要的 5 大 api 他们分别是:
- render
- state
- props
- context
- life cycle events
组件有状态组件和无状态组件, 状态组件使用可控制状态的 api,render state 和 life cycle events. 无状态组件使用 render props context.
组件设计模式, 可以将你的数据层和逻辑层分开, 通过职责区分你的组件. 你可以创建可以复用的组件, 而这些组件又可以创建出更加复杂的 UI 试图. 这对于构建 app 是极为重要的.
在组件设计模式中我们可以将组件分为:
1. 容器组件
2. 展示型组件
3. 高阶组件
4.render 回调
容器组件:
容器组件用于获取数据, 渲染他下面的子组件, 这个就是容器组件.
容器组件可以是你的数据层或者业务逻辑层, 并且使用的是 stateful api. 通过生命周期函数你可以连接你的状态管理库, 例如 redux 或者 flux. 容器组件可以传递数据和回调函数给子组件. 在容器组件的 render 方法中, 通过展示组件的组合来构建你的 UI 试图. 因为容器组件是具有状态的, 所以你需要使用 class 来声明你的组件, 而不是使用函数式组件.
在如下例子中, 有个 class component 名为 Greeting, 他有 state, 生命周期函数和 render 函数.
- class Greeting extends React.Component { constructor() {
- super();
- this.state = {
- name: "",
- };
- }
- componentDidMount() {
- // AJAX
- this.setState(() => {
- return {
- name: "William",
- };
- });
- }
- render() {
- return (
- <div>
- <h1>Hello! {this.state.name}</h1>
- </div>
- );
- }
- }
这个组件是具备状态的 class 组件. 为了让 Greeting 组件成为容器型组件, 我们需要把 UI 拆分到展示型组件中. 如下:
展示型组件:
展示型组件利用的是, props,render,context(stateless api's)
- const GreetingCard = (props) => {
- return (
- <div>
- <h1>Hello! {props.name}</h1>
- </div>
- )
- }
容器组件通过 props 传递数据和回调函数给展示型组件. 通过容器组件和展示型组件来共同封装业务逻辑, 并组合成新的组件.
- const GreetingCard = (props) => {
- return (
- <div>
- <h1>{props.name}</h1>
- </div>
- )
- }
- class Greeting extends React.Component {
- constructor() {
- super();
- this.state = {
- name: "",
- };
- }
- componentDidMount() {
- // AJAX
- this.setState(() => {
- return {
- name: "William",
- };
- });
- }
- render() {
- return (
- <div>
- <GreetingCard name={this.state.name} />
- </div>
- );
- }
- }
如上示例, 我们移除了标签元素, 并且将他放入了无状态的展示型组件中. 当然这个只是这个很简单的示例, 但是在复杂的 app 运用中, 原理都是相同的.
高阶组件:
高阶组件, 是以组件作为参数, 并且返回一个新的组件.
高阶组件可以提供数据给任意数量的组件, 并且有效的复用业务逻辑. 它是个强大的模式. 例如在 react-router 和 redux 中, 在 react-router 中你可以使用 widthRouter() 去继承方法, 并且通过 props 传递给你的组件. 在 redux 中你可以 connect 方法去传递你的 actions.
- import {withRouter} from 'react-router-dom';
- class App extends React.Component {
- constructor() {
- super();
- this.state = {path: ''}
- }
- componentDidMount() {
- let pathName = this.props.location.pathname;
- this.setState(() => {
- return {
- path: pathName,
- }
- })
- }
- render() {
- return (
- <div>
- <h1>Hi! I'm being rendered at: {this.state.path}</h1>
- </div>
- )
- }
- }
- export default withRouter(App);
如上示例, 我们通过 this.props.location.pathname 来更新状态. 通过 withRouter 方法来包裹组件. 现在我们的组件可以通过 props 来出来 react-rouoter 的方法 this.props.location.pathname;
Render callbacks
类似于高阶组件, render callbacks 或者 render props 都是用来复用组价逻辑的. 当更多的开发者倾向于高阶组件来复用业务逻辑的时候, 这里有几个原因和优点可以让你尝试下使用 render callbacks.render callsbacks 可以有效的减少命名冲突, 并且清晰的展示逻辑的来源.
- class Counter extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0,
- };
- }
- increment = () => {
- this.setState(prevState => {
- return {
- count: prevState.count + 1,
- };
- });
- };
- render() {
- return (
- <div onClick={this.increment}>{this.props.children(this.state)}</div>
- );
- }
- }
- class App extends React.Component {
- render() {
- return (
- <Counter>
- {state => (
- <div>
- <h1>The count is: {state.count}</h1>
- </div>
- )}
- </Counter>
- );
- }
- }
在 Counter 类的 render 方法中, 内嵌了 this.props.children 并且以 this.state 作为参数传入. 再 App 类中我们可以再 Counter 中包裹我们的组件来处理 Counter 的逻辑. 因此他可以处理来自 Counter 中的 state.
来源: https://www.cnblogs.com/chargo/p/9471026.html