reactjs - 在 Typescript 中实现 react-bootstrap 自定义下拉示例
问题描述
我正在尝试使用 React 功能组件在 Typescript 中的react-bootstrap 页面中实现自定义切换下拉示例。
这是我的组件代码:
import React from 'react';
import Dropdown from 'react-bootstrap/Dropdown';
import FormControl from 'react-bootstrap/FormControl';
export const DropdownSelector =() => (
<Dropdown>
<Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components">
Custom toggle
</Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu}>
<Dropdown.Item eventKey="1">Red</Dropdown.Item>
<Dropdown.Item eventKey="2">Blue</Dropdown.Item>
<Dropdown.Item eventKey="3" active>
Orange
</Dropdown.Item>
<Dropdown.Item eventKey="1">Red-Orange</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
)
// The forwardRef is important!!
// Dropdown needs access to the DOM node in order to position the Menu
const CustomToggle = React.forwardRef(({ children, onClick }, ref) => (
<a
href=""
ref={ref}
onClick={(e) => {
e.preventDefault();
onClick(e);
}}
>
{children}
▼
</a>
));
// forwardRef again here!
// Dropdown needs access to the DOM of the Menu to measure it
const CustomMenu = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
const [value, setValue] = useState('');
return (
<div
ref={ref}
style={style}
className={className}
aria-labelledby={labeledBy}
>
<FormControl
autoFocus
className="mx-3 my-2 w-auto"
placeholder="Type to filter..."
onChange={(e) => setValue(e.target.value)}
value={value}
/>
<ul className="list-unstyled">
{React.Children.toArray(children).filter(
(child) =>
!value || child.props.children.toLowerCase().startsWith(value),
)}
</ul>
</div>
);
},
);
这无法编译:
./src/components/helpers/dropdown-selector.tsx
./src/components/helpers/dropdown-selector.tsx(25,52) 中的 TypeScript 错误:
类型 '{ children?:ReactNode 上不存在属性 'onClick' ; }'。TS2339
我究竟做错了什么?
Stackblitz 沙盒版本在这里。使用那个编辑器,我看到一堆类型错误(尽管它确实运行);但是我用来开发应用程序的 IDE 不会让我运行它并出现这些错误......
解决方案
我想我确实解决了你的问题
import React, { useState } from "react";
import Dropdown from "react-bootstrap/Dropdown";
import FormControl from "react-bootstrap/FormControl";
interface IFruity {
id: number;
fruit: string;
prefix: string;
suffix?: string;
}
const fruits: IFruity[] = [
{ id: 1, fruit: "Apples", prefix: "How's about them " },
{ id: 2, fruit: "Pear", prefix: "A cracking ", suffix: "!" },
{ id: 3, fruit: "Oranges", prefix: "What rhymes with ", suffix: "?" },
{ id: 4, fruit: "Banana", prefix: "Fruit flies like a " },
{ id: 5, fruit: "Coconuts", prefix: "Oh what a lovely bunch of " },
{ id: 6, fruit: "Avocado", prefix: "Is an ", suffix: " even a fruit?" }
];
type CustomToggleProps = {
children?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {};
};
// The forwardRef is important!!
// Dropdown needs access to the DOM node in order to position the Menu
const CustomToggle = React.forwardRef(
(props: CustomToggleProps, ref: React.Ref<HTMLAnchorElement>) => (
<a
href=""
ref={ref}
onClick={e => {
e.preventDefault();
props.onClick(e);
}}
>
{props.children}
<span style={{ paddingLeft: "5px" }}>▼</span>
</a>
)
);
type CustomMenuProps = {
children?: React.ReactNode;
style?: React.CSSProperties;
className?: string;
labeledBy?: string;
};
// forwardRef again here!
// Dropdown needs access to the DOM of the Menu to measure it
const CustomMenu = React.forwardRef(
(props: CustomMenuProps, ref: React.Ref<HTMLDivElement>) => {
const [value, setValue] = useState("");
return (
<div
ref={ref}
style={props.style}
className={props.className}
aria-labelledby={props.labeledBy}
>
<FormControl
autoFocus
className="mx-3 my-2 w-auto"
placeholder="Type to filter..."
onChange={e => setValue(e.target.value)}
value={value}
/>
<ul className="list-unstyled">
{React.Children.toArray(props.children).filter(
(child: any) =>
!value || child.props.children.toLowerCase().startsWith(value)
)}
</ul>
</div>
);
}
);
export const DropdownSelector = () => {
const [selectedFruit, setSelectedFruit] = useState(0);
const theChosenFruit = () => {
const chosenFruit: IFruity = fruits.find(f => f.id === selectedFruit);
return chosenFruit
? chosenFruit.prefix + chosenFruit.fruit + (chosenFruit.suffix || "")
: "Select a fruit";
};
return (
<Dropdown onSelect={(e: string) => setSelectedFruit(Number(e))}>
<Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components">
{theChosenFruit()}
</Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu}>
{fruits.map(fruit => {
return (
<Dropdown.Item key={fruit.id} eventKey={fruit.id.toString()}>
{fruit.fruit}
</Dropdown.Item>
);
})}
</Dropdown.Menu>
</Dropdown>
);
};
推荐阅读
- webrtc - WebRTC Coturn,无法在某些网络上查看远程用户
- javascript - WebSocket 端点未得到解决:错误代码:404
- java - 使用不同的附加功能重新创建活动
- java - 如果我的按钮被点击,我如何重置计时器?
- python - 如何让python不使用破折号计算数字变量?
- amazon-web-services - 便宜的 AWS 日志聚合器
- java - 复制粘贴 exe 到 jar 的外部位置
- c# - AmazonS3Client 单个连接与每次调用的新连接 C#
- python - 在python中热图选定列的最简单方法?
- php - Laravel API 控制器的验证 JSON 响应