晴明的博客园 GitHub      CodePen      CodeWars     

[react] 无状态组件 与 高阶组件

高阶组件

通过函数和闭包,改变已有组件的行为,
本质上就是 Decorator 模式在React的一种实现。

  • 定义
import { Component } from "React" ;

export const Enhance = (ComposedComponent) => {
	return class extends Component {
		constructor() {
			this.state = { data: null };
		}
		componentDidMount() {
			this.setState({ data: 'Hello' });
		}
		render() {
			return <ComposedComponent {...this.props} data={this.state.data} />;
		}
	}
}

Enhance 是一个方法,当传入一个 Component(ComposedComponent) 的时候,
它将自动为该 Component 进行扩展并返回新的类定义。
Enhance 中就返回了一个扩展的 Component 类,为构造函数中添加了 state,
也在 React 生命周期函数 componentDidMount中添加了处理逻辑,
而 render 方法则使用了传入的参数,完成了渲染。

  • 用法

import  { Component }  from "React";
import { Enhance } from "./Enhance";

class MyComponent = class extends Component {
      render() {
          if (!this.props.data) return <div>Waiting...</div>;
          return <div>{this.props.data}</div>;
      }
}

export default Enhance(MyComponent); // Enhanced component`

  • 另一个例子

function connectPromise({promiseLoader, mapResultToProps}) {
  return Comp=> {
    return class AsyncComponent extends Component {
      constructor(props) {
        super();
        this.state = {
          result: undefined
        }
      }
      componentDidMount() {
        promiseLoader()
          .then(result=> this.setState({result}))
      }
      render() {
        return (
          <Comp {...mapResultToProps(props)} {...this.props}/>
        )
      }
    }
  }
}


const UserList = connectPromise({
    promiseLoader: loadUsers,
    mapResultToProps: result=> ({list: result.userList})
})(List); //List can be a pure component

const BookList = connectPromise({
    promiseLoader: loadBooks,
    mapResultToProps: result=> ({list: result.bookList})
})(List);

无状态组件

findDOMNode和refs都无法用于无状态组件中,无状态组件挂载时只是方法调用,没有新建实例。

当无状态组件需要使用到生命周期时,可使用高阶组件包装。

function HelloComponent(props, /* context */) {
  return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)
function Input({ label, name, value, ...props }, { defaultTheme }) {
  const { theme, autoFocus, ...rootProps } = props
  return (
    <label
      htmlFor={name}
      children={label || defaultLabel}
      {...rootProps}
    >
    <input
      name={name}
      type="text"
      value={value || ''}
      theme={theme || defaultTheme}
      {...props}
    />
  )}
Input.contextTypes = {defaultTheme: React.PropTypes.object};
posted @ 2016-12-26 18:45  晴明桑  阅读(4515)  评论(0编辑  收藏  举报