Reputation: 2033
In my Datatable the input loses focus when I type any char in the input and define the componenent inside the component. However when I put the component directly in the datatable it works. I know that the first case doesnt work because the component rerenders every time I type a character. But why does the second case work? And how can I get the first case to work without put the code directly in the datatable.
Codesandbox: https://codesandbox.io/s/test-2p30w
Dont Work (First Case)
import Datatable from "react-table";
import { useState } from "react";
const Test = () => {
const [first, setFirst] = useState("");
const [second, setSecond] = useState("");
const Field1 = () => (
<input
defaultValue={first}
onChange={(e) => setFirst(e.currentTarget.value)}
/>
);
const Field2 = () => (
<input
defaultValue={second}
onChange={(e) => setSecond(e.currentTarget.value)}
/>
);
return (
<Datatable
noText
pageSize={1}
showPagination={false}
data={[{ userName: "asdas", email: "asdsad" }]}
columns={[
{
Header: "www",
accessor: "userName",
Cell: <Field1 />
},
{
Header: "Email",
accessor: "email",
Cell: <Field2 />
}
]}
/>
);
};
export default Test;
Work (Second Case)
import Datatable from "react-table";
import { useState } from "react";
const Test = () => {
const [first, setFirst] = useState("");
const [second, setSecond] = useState("");
return (
<Datatable
noText
pageSize={1}
showPagination={false}
data={[{ userName: "asdas", email: "asdsad" }]}
columns={[
{
Header: "www",
accessor: "userName",
Cell: (
<input
defaultValue={first}
onChange={(e) => setFirst(e.currentTarget.value)}
/>
)
},
{
Header: "Email",
accessor: "email",
Cell: (
<input
defaultValue={second}
onChange={(e) => setSecond(e.currentTarget.value)}
/>
)
}
]}
/>
);
};
export default Test;
Upvotes: 2
Views: 876
Reputation: 15116
The focus gets lost because you declare the Field1
and Field2
components in the body of Test
, which means fresh components are created on each render, and any state will be lost. You can fix it by lifting the Field1
& Field2
definitions to the top-level scope and replacing the local-variable references with props (which will make them equal, so you can just use a single Field
):
const Field = ({ defaultValue, onChange }) => (
<input defaultValue={defaultValue} onChange={onChange} />
);
const Test = () => {
const [first, setFirst] = useState("");
const [second, setSecond] = useState("");
return (
<Datatable
noText
pageSize={1}
showPagination={false}
data={[{ userName: "asdas", email: "asdsad" }]}
columns={[
{
Header: "www",
accessor: "userName",
Cell: (
<Field
defaultValue={first}
onChange={(e) => setFirst(e.currentTarget.value)}
/>
)
},
{
Header: "Email",
accessor: "email",
Cell: (
<Field
defaultValue={second}
onChange={(e) => setSecond(e.currentTarget.value)}
/>
)
}
]}
/>
);
};
Upvotes: 4