使用自己的状态更改 HOC 包装器组件以响应挂钩
Change HOC wrapper component with its own state to react hooks
我目前有一个 HOC 组件,我想移植它以使用 React Hooks,基本上只是开始思考这个想法。
这个 HOC 组件基本上为包装组件提供了显示警告对话框的功能。 HOC 组件管理自己的状态,使包装的组件很容易显示警告对话框。包装的组件只需调用传递给 props 的函数即可显示它。
这是 HOC 现在的样子:
function withAlertDialog(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {
alertDialogOpen: false,
alertMessage: ""
};
}
displayAlert = message => {
this.setState({alertDialogOpen: true, alertMessage: message});
}
closeAlertDialog = () => {
this.setState({alertDialogOpen: false});
}
render() {
return (
<React.Fragment>
<WrappedComponent
onDisplayAlert={this.displayAlert}
onCloseAlert={this.closeAlertDialog} />
<MyAlertDialogComponent
open={this.state.alertDialogOpen}
onClose={this.closeAlertDialog} />
</React.Fragment>
);
}
}
}
这是一个比较简单的案例,实际使用的HOC要复杂很多,但是思路还是可以的。包装组件现在基本上可以调用 this.props.onDisplayAlert('some message here');
来显示警报。包装组件也不必在其自己的渲染函数中渲染 MyAlertDialogComponent
。基本上,包装组件不必担心 MyAlertDialogComponent
是如何处理的,它只知道调用 this.props.onDisplayAlert
会以某种方式显示一个警告对话框。重用这个 HOC 可以节省很多代码行。
如何将其更改为 React Hooks 实现?我试过环顾四周,但大多数文章和文档本身都使用带有单个包装组件的 HOC,除此之外并没有真正管理另一个组件。我想了解如何更改为 "react hooks" 意识形态,但保持相同的便利程度,即不必在每个想要使用它的组件中呈现 MyAlertDialogComponent
。
您的旧 HOC 和使用挂钩的新 HOC 之间的唯一区别是您只需将您 return 的匿名 class 从您的 HOC 更改为使用挂钩的匿名函数。
class 和 hooked-in 函数之间的转换遵循正常的转换规则,您可能会在许多在线教程中找到这些规则。对于您的示例,将您的状态转换为 useState
并将您的 class 方法转换为常规函数。
您只需将状态和这些常规函数传递给任何需要它们的组件。为您的州调用 setter 将 re-render 组件。
如果您查看下面的示例,您会看到 MyWrappedComponent
是使用 withAlertDialog
包装的,它将两个函数属性传递给 MyWrappedComponent
。这些函数在 MyWrappedComponent
内部使用来设置渲染 MyAlertDialogComponent
的状态
const { useState } = React
function withAlertDialog(WrappedComponent) {
return function(props){
const [alertState, setAlertState] = useState({
alertDialogOpen: false,
alertMessage: ""
})
const displayAlert = message => {
setAlertState({
alertDialogOpen: true,
alertMessage: message
});
}
const closeAlertDialog = () => {
setAlertState({alertDialogOpen: false});
}
return (
<React.Fragment>
<WrappedComponent
onDisplayAlert={displayAlert}
onCloseAlert={closeAlertDialog} />
<MyAlertDialogComponent
open={alertState.alertDialogOpen}
onClose={closeAlertDialog} />
</React.Fragment>
);
}
}
const MyWrappedComponent = withAlertDialog(function (props){
return (
<div>
<a onClick={props.onDisplayAlert}>Open Alert</a>
<a onClick={props.onCloseAlert}>Close Alert</a>
</div>
)
})
function MyAlertDialogComponent(props){
if(!props.open){
return null
}
return (
<div>Dialogue Open</div>
)
}
function App(){
return (
<MyWrappedComponent />
)
}
ReactDOM.render(<App />, document.querySelector('#app'))
div > a {
display : block;
padding : 10px 0;
}
<div id="app" />
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
我目前有一个 HOC 组件,我想移植它以使用 React Hooks,基本上只是开始思考这个想法。
这个 HOC 组件基本上为包装组件提供了显示警告对话框的功能。 HOC 组件管理自己的状态,使包装的组件很容易显示警告对话框。包装的组件只需调用传递给 props 的函数即可显示它。
这是 HOC 现在的样子:
function withAlertDialog(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {
alertDialogOpen: false,
alertMessage: ""
};
}
displayAlert = message => {
this.setState({alertDialogOpen: true, alertMessage: message});
}
closeAlertDialog = () => {
this.setState({alertDialogOpen: false});
}
render() {
return (
<React.Fragment>
<WrappedComponent
onDisplayAlert={this.displayAlert}
onCloseAlert={this.closeAlertDialog} />
<MyAlertDialogComponent
open={this.state.alertDialogOpen}
onClose={this.closeAlertDialog} />
</React.Fragment>
);
}
}
}
这是一个比较简单的案例,实际使用的HOC要复杂很多,但是思路还是可以的。包装组件现在基本上可以调用 this.props.onDisplayAlert('some message here');
来显示警报。包装组件也不必在其自己的渲染函数中渲染 MyAlertDialogComponent
。基本上,包装组件不必担心 MyAlertDialogComponent
是如何处理的,它只知道调用 this.props.onDisplayAlert
会以某种方式显示一个警告对话框。重用这个 HOC 可以节省很多代码行。
如何将其更改为 React Hooks 实现?我试过环顾四周,但大多数文章和文档本身都使用带有单个包装组件的 HOC,除此之外并没有真正管理另一个组件。我想了解如何更改为 "react hooks" 意识形态,但保持相同的便利程度,即不必在每个想要使用它的组件中呈现 MyAlertDialogComponent
。
您的旧 HOC 和使用挂钩的新 HOC 之间的唯一区别是您只需将您 return 的匿名 class 从您的 HOC 更改为使用挂钩的匿名函数。
class 和 hooked-in 函数之间的转换遵循正常的转换规则,您可能会在许多在线教程中找到这些规则。对于您的示例,将您的状态转换为 useState
并将您的 class 方法转换为常规函数。
您只需将状态和这些常规函数传递给任何需要它们的组件。为您的州调用 setter 将 re-render 组件。
如果您查看下面的示例,您会看到 MyWrappedComponent
是使用 withAlertDialog
包装的,它将两个函数属性传递给 MyWrappedComponent
。这些函数在 MyWrappedComponent
内部使用来设置渲染 MyAlertDialogComponent
const { useState } = React
function withAlertDialog(WrappedComponent) {
return function(props){
const [alertState, setAlertState] = useState({
alertDialogOpen: false,
alertMessage: ""
})
const displayAlert = message => {
setAlertState({
alertDialogOpen: true,
alertMessage: message
});
}
const closeAlertDialog = () => {
setAlertState({alertDialogOpen: false});
}
return (
<React.Fragment>
<WrappedComponent
onDisplayAlert={displayAlert}
onCloseAlert={closeAlertDialog} />
<MyAlertDialogComponent
open={alertState.alertDialogOpen}
onClose={closeAlertDialog} />
</React.Fragment>
);
}
}
const MyWrappedComponent = withAlertDialog(function (props){
return (
<div>
<a onClick={props.onDisplayAlert}>Open Alert</a>
<a onClick={props.onCloseAlert}>Close Alert</a>
</div>
)
})
function MyAlertDialogComponent(props){
if(!props.open){
return null
}
return (
<div>Dialogue Open</div>
)
}
function App(){
return (
<MyWrappedComponent />
)
}
ReactDOM.render(<App />, document.querySelector('#app'))
div > a {
display : block;
padding : 10px 0;
}
<div id="app" />
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>