React:文本输入在我输入时不断失去焦点
React: Text input keep loosing focus as I type
我正在构建一个表单,其中有与状态绑定的输入。问题是,当我在“订单名称”或“输出要求”字段中键入时,输入字段一直在失去焦点。我读到如果在函数内部返回表单可能会发生这种情况,但我不是这种情况。
我也确定“LabelledIconInput”不是问题,因为我在登录页面中使用它,我在那里没有这样的问题。
任何人都可以提供任何指示为什么会发生这种情况吗?
有问题的输入(这些在位于 /components/ 的单独文件中定义):
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
新订单:
interface INewOrder {}
const NewOrder: React.FC<INewOrder> = (props) => {
const [orderName, setOrderName] = useState("");
const [seasonName, setSeasonName] = useState("");
const [categoryName, setCategoryName] = useState("");
const [requirements, setRequirements] = useState("");
const [dateValue, setDateValue] = useState(null);
const [newUserInfo, setNewUserInfo] = useState({
profileImages: [],
});
const updateUploadedFiles = (files) =>
setNewUserInfo({ ...newUserInfo, profileImages: files });
const handleOrderName = (event) => {
console.log(event);
setOrderName(event);
};
const handleSeasonName = (event) => {
console.log(event);
setSeasonName(event);
};
const handleCategoryName = (event) => {
console.log(event);
setCategoryName(event);
};
const handleDateChange = (event) => {
console.log(event);
setDateValue(event);
};
const handleRequirements = (event) => {
setRequirements(event);
};
return (
<Container>
<MyForm onSubmit={null}>
<PageTitle>New Order</PageTitle>
<ProgressIndication>
<Dots></Dots>
<Dots></Dots>
<Dots></Dots>
</ProgressIndication>
<br />
<FormBackground>
<Subheading>Tell Us a bit more...</Subheading>
<LabelledIconInput
label="ORDER NAME"
value={orderName}
placeholder="Name"
onChange={handleOrderName}
></LabelledIconInput>
<br /> <br />
<MySpan>
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledDropdown
label="SERVICE CATEGORY"
selectedValue={categoryName}
placeholder="Select a Category"
options={category}
onSelectOptions={handleCategoryName}
></LabelledDropdown>
</MySpan>
<br /> <br />
<FileUploadComponent
label="UPLOAD FILES"
multiple
></FileUploadComponent>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
<br />
<LabelledDateInput
label="Expected Delivery Date"
placeholder="Select a delivery date"
dateValue={dateValue}
onChange={handleDateChange}
></LabelledDateInput>
<br />
<LabelledDropdown
label="3D Software"
width="100%"
selectedValue={software[0].value}
placeholder="Select a Category"
options={software}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
</FormBackground>
<br />
<PrimaryButton onClick={null}>Next</PrimaryButton>
</MyForm>
</Container>
);
};
带样式的组件(存在于与表单相同的文件中):
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
display: grid;
justify-content: center;
grid-template-columns: auto auto;
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
color: ${colors.theme};
text-align: center;
font-weight: 600;
`;
const FormBackground = styled("div")`
background-color: white;
border-radius: 10px;
padding: 20px;
`;
const Subheading = styled("h3")`
color: ${colors.theme};
font-weight: 500;
`;
const Dots = styled("li")<IDots>`
width: 15px;
height: 15px;
text-align: center;
line-height: 2em;
border-radius: 1em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
margin: 0 50px;
display: inline-block;
color: white;
position: relative;
&&::before {
content: "";
position: absolute;
top: 6px;
left: -100px;
width: 7em;
height: 0.2em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
z-index: -1;
}
&&:first-child::before {
display: none;
}
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
加载表单时在浏览器中出现以下警告:
[Error] Warning: Expected server HTML to contain a matching <div> in <div>.
in div (created by Styled(div))
in Styled(div) (at HyperlinkButton.tsx:21)
in HyperlinkButton (at Navbar.tsx:111)
in div (at Navbar.tsx:109)
in div (created by Styled(div))
in Styled(div) (at Navbar.tsx:108)
in div (created by Styled(div))
in Styled(div) (at Navbar.tsx:99)
in div (at Navbar.tsx:98)
in Navbar (at ProtectedPageWrapper.tsx:44)
in div (created by Styled(div))
in Styled(div) (at ProtectedPageWrapper.tsx:43)
in ProtectedPageWrapper (at new-order.tsx:48)
in Index (created by withI18nextTranslation(Index))
in withI18nextTranslation(Index) (at _app.tsx:36)
in MsalProvider (at _app.tsx:35)
in CookiesProvider (at _app.tsx:34)
in ErrorBoundary (at _app.tsx:33)
in MyApp (created by withI18nextSSR(MyApp))
in withI18nextSSR(MyApp) (created by AppWithTranslation)
in NextStaticProvider (created by withI18nextTranslation(NextStaticProvider))
in withI18nextTranslation(NextStaticProvider) (created by AppWithTranslation)
in I18nextProvider (created by AppWithTranslation)
in AppWithTranslation (created by withRouter(AppWithTranslation))
in withRouter(AppWithTranslation) (at withRedux.tsx:12)
in Provider (at withRedux.tsx:11)
in withRedux(withRouter(AppWithTranslation))
in ErrorBoundary (created by ReactDevOverlay)
in ReactDevOverlay (created by Container)
in Container (created by AppContainer)
in AppContainer
in Root
(anonymous function) (next-dev.js:60)
printWarning (react-dom.development.js:88)
error (react-dom.development.js:60)
warnForInsertedHydratedElement (react-dom.development.js:6603)
didNotFindHydratableInstance (react-dom.development.js:7803)
insertNonHydratedInstance (react-dom.development.js:16504)
tryToClaimNextHydratableInstance (react-dom.development.js:16575)
updateHostComponent (react-dom.development.js:17269)
beginWork (react-dom.development.js:23179)
performUnitOfWork (react-dom.development.js:22154)
workLoopSync (react-dom.development.js:22130)
performSyncWorkOnRoot (react-dom.development.js:21756)
scheduleUpdateOnFiber (react-dom.development.js:21188)
updateContainer (react-dom.development.js:24373)
(anonymous function) (react-dom.development.js:24758)
unbatchedUpdates (react-dom.development.js:21903)
legacyRenderSubtreeIntoContainer (react-dom.development.js:24757)
renderReactElement (index.js:742)
doRender (index.js:904)
tryCatch (runtime.js:45)
invoke (runtime.js:274)
asyncGeneratorStep (index.js:189)
_next (index.js:207)
(anonymous function) (index.js:212)
Promise
(anonymous function) (index.js:204)
_callee$ (index.js:588)
tryCatch (runtime.js:45)
invoke (runtime.js:274)
asyncGeneratorStep (index.js:189)
_next (index.js:207)
promiseReactionJob
完整代码:
import styled from "@emotion/styled";
import React, { useState } from "react";
import PrimaryButton from "../buttons/PrimaryButton";
import LabelledDateInput from "../inputs/LabelledDateInput";
import LabelledDropdown from "../inputs/LabelledDropdown";
import LabelledIconInput from "../inputs/LabelledIconInput";
import { colors } from "../../utilities/colors";
import LabelledTextArea from "../inputs/LabelledTextArea";
import FileUploadComponent from "../inputs/FileUploadComponent";
interface INewOrder {}
interface IDots {
isActive?: boolean;
}
const NewOrder: React.FC<INewOrder> = (props) => {
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
display: grid;
justify-content: center;
grid-template-columns: auto auto;
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
color: ${colors.theme};
text-align: center;
font-weight: 600;
`;
const FormBackground = styled("div")`
background-color: white;
border-radius: 10px;
padding: 20px;
`;
const Subheading = styled("h3")`
color: ${colors.theme};
font-weight: 500;
`;
const Dots = styled("li")<IDots>`
width: 15px;
height: 15px;
text-align: center;
line-height: 2em;
border-radius: 1em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
margin: 0 50px;
display: inline-block;
color: white;
position: relative;
&&::before {
content: "";
position: absolute;
top: 6px;
left: -100px;
width: 7em;
height: 0.2em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
z-index: -1;
}
&&:first-child::before {
display: none;
}
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
const [orderName, setOrderName] = useState("");
const [seasonName, setSeasonName] = useState("");
const [categoryName, setCategoryName] = useState("");
const [requirements, setRequirements] = useState("");
const [dateValue, setDateValue] = useState(null);
const [newUserInfo, setNewUserInfo] = useState({
profileImages: [],
});
const updateUploadedFiles = (files) =>
setNewUserInfo({ ...newUserInfo, profileImages: files });
const seasons = [
{
value: "New Season",
label: "New Season",
},
{
value: "Summer 2022",
label: "Summer 2022",
},
{
value: "Winter 2022",
label: "Winter 2022",
},
];
const category = [
{
value: "Style",
label: "Style",
},
{
value: "Trim",
label: "Trim",
},
{
value: "Fabric",
label: "Fabric",
},
{
value: "Block",
label: "Block",
},
];
const software = [
{
value: "3D Max",
label: "3D Max",
},
{
value: "Unity",
label: "Unity",
},
{
value: "Blender",
label: "Blender",
},
];
const handleOrderName = (event) => {
console.log(event);
setOrderName(event);
};
const handleSeasonName = (event) => {
console.log(event);
setSeasonName(event);
};
const handleCategoryName = (event) => {
console.log(event);
setCategoryName(event);
};
const handleDateChange = (event) => {
console.log(event);
setDateValue(event);
};
const handleRequirements = (event) => {
setRequirements(event);
};
const onFormSubmit = (event) => {
console.log("Form submitted...");
};
const onNextButtonClick = () => {
console.log("Next button clicked");
};
return (
<Container>
<MyForm onSubmit={onFormSubmit}>
<PageTitle>New Order</PageTitle>
<ProgressIndicator>
<Dots isActive={true}></Dots>
<Dots></Dots>
<Dots></Dots>
</ProgressIndicator>
<br />
<FormBackground>
<Subheading>Tell Us a bit more...</Subheading>
<LabelledIconInput
label="ORDER NAME"
value={orderName}
placeholder="Name"
onChange={handleOrderName}
></LabelledIconInput>
<br /> <br />
<MySpan>
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledDropdown
label="SERVICE CATEGORY"
selectedValue={categoryName}
placeholder="Select a Category"
options={category}
onSelectOptions={handleCategoryName}
></LabelledDropdown>
</MySpan>
<br /> <br />
<FileUploadComponent
label="UPLOAD FILES"
multiple
></FileUploadComponent>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
<br />
<LabelledDateInput
label="Expected Delivery Date"
placeholder="Select a delivery date"
dateValue={dateValue}
onChange={handleDateChange}
></LabelledDateInput>
<br />
<LabelledDropdown
label="3D Software"
width="100%"
selectedValue={software[0].value}
placeholder="Select a Category"
options={software}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
</FormBackground>
<br />
<PrimaryButton onClick={onNextButtonClick}>Next</PrimaryButton>
</MyForm>
</Container>
);
};
export default NewOrder;
某些东西正在触发重新渲染,这就是它失去焦点的原因。
我在 bootstrap 选项卡中遇到了类似的问题。虽然我想不通。但是我所做的方法是重新渲染状态变量,我把它放在 useEffect 中并将焦点设置回输入字段。然而,这不是一个好方法,但至少这是原因。
下面的代码就是我所做的。因此,每次更改 successfulOrderReport 时,我都会将输入字段的焦点放回去。
const searchInput = useRef();
useEffect(() => {
searchInput.current.focus();
}, [successfulorderReport]);
你可以试试这个来测试,但我建议你先看看是什么导致了重新渲染。
问题
问题是您已经在另一个 React 组件中声明了所有样式化组件。每次 NewOrder
重新呈现时,它都会重新声明 MyForm
组件,这会重新安装它及其所有表单字段组件。任何具有焦点的字段都将重新装载并失去焦点。
解决方案
Define styled components outside of the render method
It is important to define your styled components outside of the render
method, otherwise it will be recreated on every single render pass.
Defining a styled component within the render method will thwart
caching and drastically slow down rendering speed, and should be
avoided.
一个React函数组件的整个函数体是 “渲染方法”。
在其他 React 组件之外自行声明所有样式组件。
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
...
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
...
`;
const FormBackground = styled("div")`
...
`;
const Subheading = styled("h3")`
...
`;
const Dots = styled("li")<IDots>`
...
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
const NewOrder: React.FC<INewOrder> = (props) => {
...
我正在构建一个表单,其中有与状态绑定的输入。问题是,当我在“订单名称”或“输出要求”字段中键入时,输入字段一直在失去焦点。我读到如果在函数内部返回表单可能会发生这种情况,但我不是这种情况。
我也确定“LabelledIconInput”不是问题,因为我在登录页面中使用它,我在那里没有这样的问题。
任何人都可以提供任何指示为什么会发生这种情况吗?
有问题的输入(这些在位于 /components/ 的单独文件中定义):
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
新订单:
interface INewOrder {}
const NewOrder: React.FC<INewOrder> = (props) => {
const [orderName, setOrderName] = useState("");
const [seasonName, setSeasonName] = useState("");
const [categoryName, setCategoryName] = useState("");
const [requirements, setRequirements] = useState("");
const [dateValue, setDateValue] = useState(null);
const [newUserInfo, setNewUserInfo] = useState({
profileImages: [],
});
const updateUploadedFiles = (files) =>
setNewUserInfo({ ...newUserInfo, profileImages: files });
const handleOrderName = (event) => {
console.log(event);
setOrderName(event);
};
const handleSeasonName = (event) => {
console.log(event);
setSeasonName(event);
};
const handleCategoryName = (event) => {
console.log(event);
setCategoryName(event);
};
const handleDateChange = (event) => {
console.log(event);
setDateValue(event);
};
const handleRequirements = (event) => {
setRequirements(event);
};
return (
<Container>
<MyForm onSubmit={null}>
<PageTitle>New Order</PageTitle>
<ProgressIndication>
<Dots></Dots>
<Dots></Dots>
<Dots></Dots>
</ProgressIndication>
<br />
<FormBackground>
<Subheading>Tell Us a bit more...</Subheading>
<LabelledIconInput
label="ORDER NAME"
value={orderName}
placeholder="Name"
onChange={handleOrderName}
></LabelledIconInput>
<br /> <br />
<MySpan>
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledDropdown
label="SERVICE CATEGORY"
selectedValue={categoryName}
placeholder="Select a Category"
options={category}
onSelectOptions={handleCategoryName}
></LabelledDropdown>
</MySpan>
<br /> <br />
<FileUploadComponent
label="UPLOAD FILES"
multiple
></FileUploadComponent>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
<br />
<LabelledDateInput
label="Expected Delivery Date"
placeholder="Select a delivery date"
dateValue={dateValue}
onChange={handleDateChange}
></LabelledDateInput>
<br />
<LabelledDropdown
label="3D Software"
width="100%"
selectedValue={software[0].value}
placeholder="Select a Category"
options={software}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
</FormBackground>
<br />
<PrimaryButton onClick={null}>Next</PrimaryButton>
</MyForm>
</Container>
);
};
带样式的组件(存在于与表单相同的文件中):
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
display: grid;
justify-content: center;
grid-template-columns: auto auto;
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
color: ${colors.theme};
text-align: center;
font-weight: 600;
`;
const FormBackground = styled("div")`
background-color: white;
border-radius: 10px;
padding: 20px;
`;
const Subheading = styled("h3")`
color: ${colors.theme};
font-weight: 500;
`;
const Dots = styled("li")<IDots>`
width: 15px;
height: 15px;
text-align: center;
line-height: 2em;
border-radius: 1em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
margin: 0 50px;
display: inline-block;
color: white;
position: relative;
&&::before {
content: "";
position: absolute;
top: 6px;
left: -100px;
width: 7em;
height: 0.2em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
z-index: -1;
}
&&:first-child::before {
display: none;
}
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
加载表单时在浏览器中出现以下警告:
[Error] Warning: Expected server HTML to contain a matching <div> in <div>.
in div (created by Styled(div))
in Styled(div) (at HyperlinkButton.tsx:21)
in HyperlinkButton (at Navbar.tsx:111)
in div (at Navbar.tsx:109)
in div (created by Styled(div))
in Styled(div) (at Navbar.tsx:108)
in div (created by Styled(div))
in Styled(div) (at Navbar.tsx:99)
in div (at Navbar.tsx:98)
in Navbar (at ProtectedPageWrapper.tsx:44)
in div (created by Styled(div))
in Styled(div) (at ProtectedPageWrapper.tsx:43)
in ProtectedPageWrapper (at new-order.tsx:48)
in Index (created by withI18nextTranslation(Index))
in withI18nextTranslation(Index) (at _app.tsx:36)
in MsalProvider (at _app.tsx:35)
in CookiesProvider (at _app.tsx:34)
in ErrorBoundary (at _app.tsx:33)
in MyApp (created by withI18nextSSR(MyApp))
in withI18nextSSR(MyApp) (created by AppWithTranslation)
in NextStaticProvider (created by withI18nextTranslation(NextStaticProvider))
in withI18nextTranslation(NextStaticProvider) (created by AppWithTranslation)
in I18nextProvider (created by AppWithTranslation)
in AppWithTranslation (created by withRouter(AppWithTranslation))
in withRouter(AppWithTranslation) (at withRedux.tsx:12)
in Provider (at withRedux.tsx:11)
in withRedux(withRouter(AppWithTranslation))
in ErrorBoundary (created by ReactDevOverlay)
in ReactDevOverlay (created by Container)
in Container (created by AppContainer)
in AppContainer
in Root
(anonymous function) (next-dev.js:60)
printWarning (react-dom.development.js:88)
error (react-dom.development.js:60)
warnForInsertedHydratedElement (react-dom.development.js:6603)
didNotFindHydratableInstance (react-dom.development.js:7803)
insertNonHydratedInstance (react-dom.development.js:16504)
tryToClaimNextHydratableInstance (react-dom.development.js:16575)
updateHostComponent (react-dom.development.js:17269)
beginWork (react-dom.development.js:23179)
performUnitOfWork (react-dom.development.js:22154)
workLoopSync (react-dom.development.js:22130)
performSyncWorkOnRoot (react-dom.development.js:21756)
scheduleUpdateOnFiber (react-dom.development.js:21188)
updateContainer (react-dom.development.js:24373)
(anonymous function) (react-dom.development.js:24758)
unbatchedUpdates (react-dom.development.js:21903)
legacyRenderSubtreeIntoContainer (react-dom.development.js:24757)
renderReactElement (index.js:742)
doRender (index.js:904)
tryCatch (runtime.js:45)
invoke (runtime.js:274)
asyncGeneratorStep (index.js:189)
_next (index.js:207)
(anonymous function) (index.js:212)
Promise
(anonymous function) (index.js:204)
_callee$ (index.js:588)
tryCatch (runtime.js:45)
invoke (runtime.js:274)
asyncGeneratorStep (index.js:189)
_next (index.js:207)
promiseReactionJob
完整代码:
import styled from "@emotion/styled";
import React, { useState } from "react";
import PrimaryButton from "../buttons/PrimaryButton";
import LabelledDateInput from "../inputs/LabelledDateInput";
import LabelledDropdown from "../inputs/LabelledDropdown";
import LabelledIconInput from "../inputs/LabelledIconInput";
import { colors } from "../../utilities/colors";
import LabelledTextArea from "../inputs/LabelledTextArea";
import FileUploadComponent from "../inputs/FileUploadComponent";
interface INewOrder {}
interface IDots {
isActive?: boolean;
}
const NewOrder: React.FC<INewOrder> = (props) => {
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
display: grid;
justify-content: center;
grid-template-columns: auto auto;
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
color: ${colors.theme};
text-align: center;
font-weight: 600;
`;
const FormBackground = styled("div")`
background-color: white;
border-radius: 10px;
padding: 20px;
`;
const Subheading = styled("h3")`
color: ${colors.theme};
font-weight: 500;
`;
const Dots = styled("li")<IDots>`
width: 15px;
height: 15px;
text-align: center;
line-height: 2em;
border-radius: 1em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
margin: 0 50px;
display: inline-block;
color: white;
position: relative;
&&::before {
content: "";
position: absolute;
top: 6px;
left: -100px;
width: 7em;
height: 0.2em;
background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
z-index: -1;
}
&&:first-child::before {
display: none;
}
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
const [orderName, setOrderName] = useState("");
const [seasonName, setSeasonName] = useState("");
const [categoryName, setCategoryName] = useState("");
const [requirements, setRequirements] = useState("");
const [dateValue, setDateValue] = useState(null);
const [newUserInfo, setNewUserInfo] = useState({
profileImages: [],
});
const updateUploadedFiles = (files) =>
setNewUserInfo({ ...newUserInfo, profileImages: files });
const seasons = [
{
value: "New Season",
label: "New Season",
},
{
value: "Summer 2022",
label: "Summer 2022",
},
{
value: "Winter 2022",
label: "Winter 2022",
},
];
const category = [
{
value: "Style",
label: "Style",
},
{
value: "Trim",
label: "Trim",
},
{
value: "Fabric",
label: "Fabric",
},
{
value: "Block",
label: "Block",
},
];
const software = [
{
value: "3D Max",
label: "3D Max",
},
{
value: "Unity",
label: "Unity",
},
{
value: "Blender",
label: "Blender",
},
];
const handleOrderName = (event) => {
console.log(event);
setOrderName(event);
};
const handleSeasonName = (event) => {
console.log(event);
setSeasonName(event);
};
const handleCategoryName = (event) => {
console.log(event);
setCategoryName(event);
};
const handleDateChange = (event) => {
console.log(event);
setDateValue(event);
};
const handleRequirements = (event) => {
setRequirements(event);
};
const onFormSubmit = (event) => {
console.log("Form submitted...");
};
const onNextButtonClick = () => {
console.log("Next button clicked");
};
return (
<Container>
<MyForm onSubmit={onFormSubmit}>
<PageTitle>New Order</PageTitle>
<ProgressIndicator>
<Dots isActive={true}></Dots>
<Dots></Dots>
<Dots></Dots>
</ProgressIndicator>
<br />
<FormBackground>
<Subheading>Tell Us a bit more...</Subheading>
<LabelledIconInput
label="ORDER NAME"
value={orderName}
placeholder="Name"
onChange={handleOrderName}
></LabelledIconInput>
<br /> <br />
<MySpan>
<LabelledDropdown
label="SEASON*"
selectedValue={seasonName}
placeholder="Select a season"
options={seasons}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
<LabelledDropdown
label="SERVICE CATEGORY"
selectedValue={categoryName}
placeholder="Select a Category"
options={category}
onSelectOptions={handleCategoryName}
></LabelledDropdown>
</MySpan>
<br /> <br />
<FileUploadComponent
label="UPLOAD FILES"
multiple
></FileUploadComponent>
<LabelledTextArea
label="OUTPUT REQUIREMENT"
value={requirements}
placeholder={null}
onChange={handleRequirements}
></LabelledTextArea>
<br />
<LabelledDateInput
label="Expected Delivery Date"
placeholder="Select a delivery date"
dateValue={dateValue}
onChange={handleDateChange}
></LabelledDateInput>
<br />
<LabelledDropdown
label="3D Software"
width="100%"
selectedValue={software[0].value}
placeholder="Select a Category"
options={software}
onSelectOptions={handleSeasonName}
></LabelledDropdown>
</FormBackground>
<br />
<PrimaryButton onClick={onNextButtonClick}>Next</PrimaryButton>
</MyForm>
</Container>
);
};
export default NewOrder;
某些东西正在触发重新渲染,这就是它失去焦点的原因。
我在 bootstrap 选项卡中遇到了类似的问题。虽然我想不通。但是我所做的方法是重新渲染状态变量,我把它放在 useEffect 中并将焦点设置回输入字段。然而,这不是一个好方法,但至少这是原因。
下面的代码就是我所做的。因此,每次更改 successfulOrderReport 时,我都会将输入字段的焦点放回去。
const searchInput = useRef();
useEffect(() => {
searchInput.current.focus();
}, [successfulorderReport]);
你可以试试这个来测试,但我建议你先看看是什么导致了重新渲染。
问题
问题是您已经在另一个 React 组件中声明了所有样式化组件。每次 NewOrder
重新呈现时,它都会重新声明 MyForm
组件,这会重新安装它及其所有表单字段组件。任何具有焦点的字段都将重新装载并失去焦点。
解决方案
Define styled components outside of the render method
It is important to define your styled components outside of the render method, otherwise it will be recreated on every single render pass. Defining a styled component within the render method will thwart caching and drastically slow down rendering speed, and should be avoided.
一个React函数组件的整个函数体是 “渲染方法”。
在其他 React 组件之外自行声明所有样式组件。
const MyForm = styled("form")`
margin: auto;
`;
const Container = styled("div")`
...
`;
const MySpan = styled("span")``;
const PageTitle = styled("h2")`
...
`;
const FormBackground = styled("div")`
...
`;
const Subheading = styled("h3")`
...
`;
const Dots = styled("li")<IDots>`
...
`;
const ProgressIndicator = styled("div")`
text-align: center;
`;
const NewOrder: React.FC<INewOrder> = (props) => {
...