Material UI V5 <ListItemButton> onClick 不工作
Material UI V5 <ListItemButton> onClick not working
我使用 Link
API 创建了一个搜索建议列表。但是 onClick 处理程序没有按预期触发。我应该如何更正它?
这是我的列表代码
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{topResponses.map((response, index) => {
return (
<>
<ListItemButton
id={response}
sx={{
paddingTop: "20px",
paddingBottom: "10px",
border: "2px solid red",
}}
onClick={(event) => {
console.log("clicked");
}}
>
<ListItemText
primary={response}
primaryTypographyProps={{
fontSize: "18px",
fontWeight: "bold",
}}
/>
{/* <p>{response}</p> */}
</ListItemButton>
<Divider variant="middle" textAlign="center" />
</>
);
})}
</List>
</Paper>
一件事可能是因为它是一个搜索建议,我设置了一个处理程序,一旦焦点从搜索栏中消失就会触发。所以当我点击搜索建议时,它应该被触发。这会是问题所在吗?
我想我遇到了问题。当搜索栏上的焦点发生变化时,我有一个焦点处理程序可以切换 on/off。据我所知,当我单击搜索建议时,此焦点处理程序会触发 re-render 而根本不会触发 onClick
函数。]
我通过在焦点处理程序上添加 100ms-200ms 的 setTimeout
来稍微延迟它来解决这个问题,这就成功了。
有人知道更好的处理方法吗?
P.S 这是我的完整代码
import React from "react";
import {
Paper,
Box,
TextField,
Button,
ListItemText,
List,
Divider,
ListItemButton,
} from "@mui/material";
import { useState, useRef } from "react";
const topResponses = ["HTML", "Senior", "Junior", "React", "CSS"];
const searchSuggestions = [
"Fullstack",
"Midweight",
"Python",
"React",
"JavaScript",
"Sass",
"CSS",
"Backend",
"Junior",
"Ruby",
"RoR",
"HTML",
"Frontend",
"Vue",
"Django",
];
const TopSuggestions = ({ filterHandler }) => {
return (
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{topResponses.map((response, index) => {
return (
<>
<ListItemButton
key={index}
sx={{
paddingTop: "20px",
paddingBottom: "10px",
}}
onClick={(event) => {
console.log("top suggestion clicked")
filterHandler(event.target.textContent);
}}
>
<ListItemText
primary={response}
primaryTypographyProps={{
fontSize: "18px",
fontWeight: "bold",
}}
/>
{/* <p>{response}</p> */}
</ListItemButton>
<Divider variant="middle" textAlign="center" />
</>
);
})}
</List>
</Paper>
);
};
const Suggestions = ({ responses }) => {
return (
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{responses.map((resp) => (
<>
{resp}
<Divider variant="middle" textAlign="center" />
</>
))}
</List>
</Paper>
);
};
const SearchBar = ({ filterHandler }) => {
const [searchResponses, setSearchResponses] = useState([]);
const [isFocused, setFocus] = useState(false);
const searchRef = useRef(null);
const [showSuggestions, setSuggestions] = useState(false);
const [searchValue, setSearchValue] = useState("");
const buildSuggestions = (eventValue) => {
setSearchResponses(
searchSuggestions
.filter((suggestion) => {
const lowerSuggestion = suggestion.toLowerCase();
const val = eventValue.toLowerCase();
return lowerSuggestion.indexOf(val) > -1;
})
.map((suggestion) => {
const lowerSuggestion = suggestion.toLowerCase();
const val = eventValue.toLowerCase();
const ind = lowerSuggestion.indexOf(val);
return (
<ListItemButton
sx={{
paddingTop: "20px",
paddingBottom: "10px",
fontSize: "18px",
fontWeight: "bold",
}}
onClick={(event) => {
console.log("build suggestions item clicked", event);
filterHandler(event.target.textContent);
}}
>
{suggestion.substring(0, ind)}
<mark style={{ backgroundColor: "#f7e7d0" }}>
{suggestion.substring(ind, ind + val.length)}
</mark>
{suggestion.substring(ind + val.length, suggestion.length)}
</ListItemButton>
);
})
);
};
const handleOnChange = (event) => {
const eventValue = event.target.value;
console.log("current value is ", eventValue);
if (eventValue !== "") {
setSuggestions(false);
} else {
setSuggestions(true);
}
setSearchValue(eventValue);
buildSuggestions(eventValue);
};
return (
<Box
sx={{
marginTop: "-30px",
width: "100%",
marginBottom: "24px",
}}
>
<Paper
elevation={5}
sx={{
padding: "20px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<TextField
variant="standard"
sx={{
color: "#2B3939",
}}
fullWidth
onFocus={() => {
setFocus(true);
setSuggestions(true);
if (searchValue !== "") buildSuggestions(searchValue);
}}
onBlur={() => {
//Here's my focus handler
setTimeout(() => {
setFocus(false);
setSuggestions(false);
}, 200);
// setFocus(false);
// setSuggestions(false);
}}
onChange={handleOnChange}
inputRef={searchRef}
InputProps={{
disableUnderline: true,
placeholder: "Search",
style: {
color: "black",
fontWeight: "bold",
fontSize: "18px",
},
}}
/>
<Button
variant="text"
sx={{
textTransform: "none",
color: "#C5C5C5",
fontWeight: "bold",
fontSize: "14px",
}}
onClick={() => {
const val = searchRef.current.value.toLowerCase();
const index = searchSuggestions.findIndex((element) => {
return element.toLowerCase() === val;
});
if (index > -1) filterHandler(searchSuggestions[index]);
else filterHandler(searchRef.current.value);
}}
>
Submit
</Button>
</Paper>
{isFocused && showSuggestions && searchValue === "" && (
<TopSuggestions
filterHandler={filterHandler}
/>
)}
{isFocused && !showSuggestions && searchValue !== "" && (
<Suggestions responses={searchResponses} />
)}
</Box>
);
};
export default SearchBar;
我使用 Link
API 创建了一个搜索建议列表。但是 onClick 处理程序没有按预期触发。我应该如何更正它?
这是我的列表代码
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{topResponses.map((response, index) => {
return (
<>
<ListItemButton
id={response}
sx={{
paddingTop: "20px",
paddingBottom: "10px",
border: "2px solid red",
}}
onClick={(event) => {
console.log("clicked");
}}
>
<ListItemText
primary={response}
primaryTypographyProps={{
fontSize: "18px",
fontWeight: "bold",
}}
/>
{/* <p>{response}</p> */}
</ListItemButton>
<Divider variant="middle" textAlign="center" />
</>
);
})}
</List>
</Paper>
一件事可能是因为它是一个搜索建议,我设置了一个处理程序,一旦焦点从搜索栏中消失就会触发。所以当我点击搜索建议时,它应该被触发。这会是问题所在吗?
我想我遇到了问题。当搜索栏上的焦点发生变化时,我有一个焦点处理程序可以切换 on/off。据我所知,当我单击搜索建议时,此焦点处理程序会触发 re-render 而根本不会触发 onClick
函数。]
我通过在焦点处理程序上添加 100ms-200ms 的 setTimeout
来稍微延迟它来解决这个问题,这就成功了。
有人知道更好的处理方法吗?
P.S 这是我的完整代码
import React from "react";
import {
Paper,
Box,
TextField,
Button,
ListItemText,
List,
Divider,
ListItemButton,
} from "@mui/material";
import { useState, useRef } from "react";
const topResponses = ["HTML", "Senior", "Junior", "React", "CSS"];
const searchSuggestions = [
"Fullstack",
"Midweight",
"Python",
"React",
"JavaScript",
"Sass",
"CSS",
"Backend",
"Junior",
"Ruby",
"RoR",
"HTML",
"Frontend",
"Vue",
"Django",
];
const TopSuggestions = ({ filterHandler }) => {
return (
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{topResponses.map((response, index) => {
return (
<>
<ListItemButton
key={index}
sx={{
paddingTop: "20px",
paddingBottom: "10px",
}}
onClick={(event) => {
console.log("top suggestion clicked")
filterHandler(event.target.textContent);
}}
>
<ListItemText
primary={response}
primaryTypographyProps={{
fontSize: "18px",
fontWeight: "bold",
}}
/>
{/* <p>{response}</p> */}
</ListItemButton>
<Divider variant="middle" textAlign="center" />
</>
);
})}
</List>
</Paper>
);
};
const Suggestions = ({ responses }) => {
return (
<Paper
elevation={5}
sx={{ maxWidth: { xs: "100%", md: "45%" }, marginTop: "10px" }}
>
<List sx={{ paddingTop: "20px", paddingBottom: "30px" }}>
{responses.map((resp) => (
<>
{resp}
<Divider variant="middle" textAlign="center" />
</>
))}
</List>
</Paper>
);
};
const SearchBar = ({ filterHandler }) => {
const [searchResponses, setSearchResponses] = useState([]);
const [isFocused, setFocus] = useState(false);
const searchRef = useRef(null);
const [showSuggestions, setSuggestions] = useState(false);
const [searchValue, setSearchValue] = useState("");
const buildSuggestions = (eventValue) => {
setSearchResponses(
searchSuggestions
.filter((suggestion) => {
const lowerSuggestion = suggestion.toLowerCase();
const val = eventValue.toLowerCase();
return lowerSuggestion.indexOf(val) > -1;
})
.map((suggestion) => {
const lowerSuggestion = suggestion.toLowerCase();
const val = eventValue.toLowerCase();
const ind = lowerSuggestion.indexOf(val);
return (
<ListItemButton
sx={{
paddingTop: "20px",
paddingBottom: "10px",
fontSize: "18px",
fontWeight: "bold",
}}
onClick={(event) => {
console.log("build suggestions item clicked", event);
filterHandler(event.target.textContent);
}}
>
{suggestion.substring(0, ind)}
<mark style={{ backgroundColor: "#f7e7d0" }}>
{suggestion.substring(ind, ind + val.length)}
</mark>
{suggestion.substring(ind + val.length, suggestion.length)}
</ListItemButton>
);
})
);
};
const handleOnChange = (event) => {
const eventValue = event.target.value;
console.log("current value is ", eventValue);
if (eventValue !== "") {
setSuggestions(false);
} else {
setSuggestions(true);
}
setSearchValue(eventValue);
buildSuggestions(eventValue);
};
return (
<Box
sx={{
marginTop: "-30px",
width: "100%",
marginBottom: "24px",
}}
>
<Paper
elevation={5}
sx={{
padding: "20px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<TextField
variant="standard"
sx={{
color: "#2B3939",
}}
fullWidth
onFocus={() => {
setFocus(true);
setSuggestions(true);
if (searchValue !== "") buildSuggestions(searchValue);
}}
onBlur={() => {
//Here's my focus handler
setTimeout(() => {
setFocus(false);
setSuggestions(false);
}, 200);
// setFocus(false);
// setSuggestions(false);
}}
onChange={handleOnChange}
inputRef={searchRef}
InputProps={{
disableUnderline: true,
placeholder: "Search",
style: {
color: "black",
fontWeight: "bold",
fontSize: "18px",
},
}}
/>
<Button
variant="text"
sx={{
textTransform: "none",
color: "#C5C5C5",
fontWeight: "bold",
fontSize: "14px",
}}
onClick={() => {
const val = searchRef.current.value.toLowerCase();
const index = searchSuggestions.findIndex((element) => {
return element.toLowerCase() === val;
});
if (index > -1) filterHandler(searchSuggestions[index]);
else filterHandler(searchRef.current.value);
}}
>
Submit
</Button>
</Paper>
{isFocused && showSuggestions && searchValue === "" && (
<TopSuggestions
filterHandler={filterHandler}
/>
)}
{isFocused && !showSuggestions && searchValue !== "" && (
<Suggestions responses={searchResponses} />
)}
</Box>
);
};
export default SearchBar;