使用 React Hooks 的可重用下拉列表
Reusable Dropdown with React Hooks
正如我从 React 文档中了解到的那样,使用钩子不需要大的代码重构,并且可以轻松地包含在现有代码中。我想制作可重用的下拉菜单,从反应组件渲染方法调用。
这是我的代码:
//navigation.js
import {DropdownToggler} from './dropdown.js';
export class ErrorTriangle extends Component {
render(){
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
}
//dropdown.js
import React, {useEffect, useRef, useState} from "react";
import {store} from "../api/redux/store";
const DropdownToggler = (props) => {
const myRef = useRef(null);
const [showField, setShow] = useState(false);
const isMobile = store.getState().isMobile;
const remove = (e) => {
e.stopPropagation();
if (myRef && myRef.current.contains(e.target)) {
return
}
setShow(false);
if (isMobile===true) {
document.removeEventListener('touchend', remove, false)
} else {
document.removeEventListener('mouseup', remove, false)
}
};
const show = (e) => {
e.stopPropagation();
if (showField) {
return
}
setShow(true);
if (isMobile===true) {
document.addEventListener('touchend', remove, false)
} else {
document.addEventListener('mouseup', remove, false)
}
};
return (
<>
{React.cloneElement(props.uiElement.toggler, {
onTouchEnd: (e) => show(e),
onMouseUp: isMobile ? null : (e) => show(e)
})}
{showField ? React.cloneElement(props.uiElement.field, {ref: node => myRef.current= node}) : null}
</>
)
};
export {DropdownToggler};
并得到错误:Hooks can only be called inside of a function component.
我已经检查过有关此问题的现有信息:
- react-hot-loader 版本为 4.8.0
- 我的 react 和 react-dom 是同一个版本 16.8.4;
我的 babel-config 包含:
'use strict';
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ["@babel/plugin-proposal-class-properties", "jsx-control-statements", "react-hot-loader/babel"],
};
也许问题是我违反了钩子的规则https://reactjs.org/warnings/invalid-hook-call-warning.html。将感谢详细的解释(示例)或为什么这不起作用的想法。
改变
export class ErrorTriangle extends Component {
render(){
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
}
到
export function ErrorTriangle (props) {
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
或
改变
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
到
{<DropdownToggler uiElement={{
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}}/>
}
说明
简单地说,如果您使用 class,您应该像这样调用您的组件函数 <Component />
而不是像普通函数 Component()
或者您可以从使用 class 到使用组件函数
正如我从 React 文档中了解到的那样,使用钩子不需要大的代码重构,并且可以轻松地包含在现有代码中。我想制作可重用的下拉菜单,从反应组件渲染方法调用。 这是我的代码:
//navigation.js
import {DropdownToggler} from './dropdown.js';
export class ErrorTriangle extends Component {
render(){
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
}
//dropdown.js
import React, {useEffect, useRef, useState} from "react";
import {store} from "../api/redux/store";
const DropdownToggler = (props) => {
const myRef = useRef(null);
const [showField, setShow] = useState(false);
const isMobile = store.getState().isMobile;
const remove = (e) => {
e.stopPropagation();
if (myRef && myRef.current.contains(e.target)) {
return
}
setShow(false);
if (isMobile===true) {
document.removeEventListener('touchend', remove, false)
} else {
document.removeEventListener('mouseup', remove, false)
}
};
const show = (e) => {
e.stopPropagation();
if (showField) {
return
}
setShow(true);
if (isMobile===true) {
document.addEventListener('touchend', remove, false)
} else {
document.addEventListener('mouseup', remove, false)
}
};
return (
<>
{React.cloneElement(props.uiElement.toggler, {
onTouchEnd: (e) => show(e),
onMouseUp: isMobile ? null : (e) => show(e)
})}
{showField ? React.cloneElement(props.uiElement.field, {ref: node => myRef.current= node}) : null}
</>
)
};
export {DropdownToggler};
并得到错误:Hooks can only be called inside of a function component. 我已经检查过有关此问题的现有信息:
- react-hot-loader 版本为 4.8.0
- 我的 react 和 react-dom 是同一个版本 16.8.4;
我的 babel-config 包含:
'use strict'; module.exports = { presets: ['@babel/preset-env', '@babel/preset-react'], plugins: ["@babel/plugin-proposal-class-properties", "jsx-control-statements", "react-hot-loader/babel"], };
也许问题是我违反了钩子的规则https://reactjs.org/warnings/invalid-hook-call-warning.html。将感谢详细的解释(示例)或为什么这不起作用的想法。
改变
export class ErrorTriangle extends Component {
render(){
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
}
到
export function ErrorTriangle (props) {
return(
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
)
}
或
改变
{DropdownToggler({uiElement: {
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}})
}
到
{<DropdownToggler uiElement={{
toggler: <img src={MyImg}/>,
field: <div className={'errorMessage'}>
<p>Dropdown content</p>
</div >
}}/>
}
说明
简单地说,如果您使用 class,您应该像这样调用您的组件函数 <Component />
而不是像普通函数 Component()
或者您可以从使用 class 到使用组件函数