高階組件
通過函數和閉包,改變已有組件的行為,
本質上就是 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};