我正在构建一个带有许多钩子的表单,在提交时会填充表格。到目前为止,我在一个应用程序中拥有所有功能 - 一切 - 。
const [id, setId] = React.useState<number>(0);
const [firstName, setFirstName] = React.useState<string>('')
const [middleName, setMiddleName] = React.useState<string>('')
const [lastName, setLastName] = React.useState<string>('')
const [birthDay, setBirthDay] = React.useState<number>(0)
const [birthMonth, setBirthMonth] = React.useState<number | string>(0)
const [birthYear, setBirthYear] = React.useState<number>(0)
const [birthState, setBirthState] = React.useState<string>('')
const [birthCounty, setBirthCounty] = React.useState<string>('')
const [birthTown, setBirthTown] = React.useState<string>('')
const [people, setPeople] = React.useState<any[]>([])
当提交表单时,最终状态钩子“people”会填充一个表。呈现表格的函数取决于 people 数组。每个钩子对应表中的一列(保存最后一个钩子,它填充表):
const renderHeader = () => {
let columns = [
'id',
'firstName',
'middleName',
'lastName',
'birthDay',
'birthMonth',
'birthYear',
'birthState',
'birthCounty',
'birthTown'
]
if (people.length === 0) {
return <h3>add people to the array to view table</h3>
} else if (people.length > 0) {
return columns.map((col: string, index: number) => {
return <th key={index}>{col.toUpperCase()}</th>
});
}
}
const renderBody = () => {
return people.map(({
id,
firstName,
middleName,
lastName,
birthDay,
birthMonth,
birthYear,
birthState,
birthCounty,
birthTown
}) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{firstName}</td>
<td>{middleName}</td>
<td>{lastName}</td>
<td>{birthDay}</td>
<td>{birthMonth}</td>
<td>{birthYear}</td>
<td>{birthTown}</td>
<td>{birthCounty}</td>
<td>{birthState}</td>
</tr>
);
});
}
我想把 App 分成两个组件:一个 Form 组件和一个 Table 组件。如果我将它们分开,我不知道如何将人钩传递到桌子上。有没有不使用 Redux 的方法来做到这一点?
以下是所有代码供参考:
import React from 'react';
import './App.css';
import { states } from './states';
import getCounties from './getCounties';
function App() {
const [id, setId] = React.useState<number>(0);
const [firstName, setFirstName] = React.useState<string>('')
const [middleName, setMiddleName] = React.useState<string>('')
const [lastName, setLastName] = React.useState<string>('')
const [birthDay, setBirthDay] = React.useState<number>(0)
const [birthMonth, setBirthMonth] = React.useState<number | string>(0)
const [birthYear, setBirthYear] = React.useState<number>(0)
const [birthState, setBirthState] = React.useState<string>('')
const [birthCounty, setBirthCounty] = React.useState<string>('')
const [birthTown, setBirthTown] = React.useState<string>('')
const [people, setPeople] = React.useState<any[]>([])
const renderHeader = () => {
let columns = [
'id',
'firstName',
'middleName',
'lastName',
'birthDay',
'birthMonth',
'birthYear',
'birthState',
'birthCounty',
'birthTown'
]
if (people.length === 0) {
return <h3>add people to the array to view table</h3>
} else if (people.length > 0) {
return columns.map((col: string, index: number) => {
return <th key={index}>{col.toUpperCase()}</th>
});
}
}
const renderBody = () => {
return people.map(({
id,
firstName,
middleName,
lastName,
birthDay,
birthMonth,
birthYear,
birthState,
birthCounty,
birthTown
}) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{firstName}</td>
<td>{middleName}</td>
<td>{lastName}</td>
<td>{birthDay}</td>
<td>{birthMonth}</td>
<td>{birthYear}</td>
<td>{birthTown}</td>
<td>{birthCounty}</td>
<td>{birthState}</td>
</tr>
);
});
}
const handleFirstNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFirstName(e.target.value);
}
const handleMiddleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setMiddleName(e.target.value);
}
const handleLastNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setLastName(e.target.value);
}
const handleBirthYearChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setBirthYear(e.target.valueAsNumber);
}
const handleBirthMonthChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setBirthMonth(e.target.value);
}
const handleBirthDayChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setBirthDay(e.target.valueAsNumber);
}
const handleBirthTownChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setBirthTown(e.target.value);
}
const handleBirthCountyChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setBirthCounty(e.currentTarget.value);
}
const handleBirthStateChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setBirthState(e.currentTarget.value)
}
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
setPeople(people => [...people, {
id,
firstName,
middleName,
lastName,
birthDay,
birthMonth,
birthYear,
birthState,
birthCounty,
birthTown
}]);
setId(id + 1);
setFirstName('');
setMiddleName('');
setLastName('');
setBirthDay(0);
setBirthMonth('');
setBirthYear(0);
setBirthTown('');
setBirthCounty('');
setBirthState('');
}
return (
<div className="App">
<h1><code>Kyle's Genealogy Thing</code></h1>
<table id="people">
<thead>
<tr>{renderHeader()}</tr>
</thead>
<tbody>
{renderBody()}
</tbody>
</table>
<form onSubmit={onSubmit}>
<div>
<input
required
value={firstName}
placeholder='first name'
id='firstName'
name='firstName'
onChange={handleFirstNameChange}
/>
<input
value={middleName}
placeholder='middle name'
id='middleName'
name='middleName'
onChange={handleMiddleNameChange}
/>
<input
required
value={lastName}
placeholder="last name"
onChange={handleLastNameChange}
/>
</div>
<div>
<label htmlFor="birthDay">day of birth</label>
<input
name="birthDay"
id="birthDay"
type='number'
min='1'
max='31'
onChange={handleBirthDayChange}
/>
<label htmlFor='birthMonth'>month of birth</label>
<input
name='birthMonth'
id='birthMonth'
min='1'
max='12'
onChange={handleBirthMonthChange}
/>
<label htmlFor='birthYear'>year of birth</label>
<input
name='birthYear'
id='birthYear'
type='number'
value={birthYear}
onChange={handleBirthYearChange}
/>
</div>
<div>
<label>state of birth</label>
<select
value={birthState}
placeholder='state of birth'
onChange={handleBirthStateChange}>
{states.map(state =>
<option key={state} value={state}>
{state}
</option>
)}
</select>
<label>county of birth</label>
<select
value={birthCounty}
placeholder='county of birth'
onChange={handleBirthCountyChange}>
{getCounties(birthState)}
</select>
<label>town or city of birth</label>
<input
value={birthTown}
placeholder='town or city of birth'
onChange={handleBirthTownChange}
/>
</div>
<button>submit</button>
</form>
</div>
);
}
export default App;
我也写了一个供人使用的接口,但是我没能实现它……我想这可能是另一个问题,但这里是我写的接口供参考:
export interface Place {
state: string;
county: string;
town: string;
}
export interface Date {
day: number;
month: number | string;
year: number;
}
export interface Name {
first: string;
middle?: string;
last: string;
}
export interface Person {
id: number;
name: Name;
birthdate: Date;
birthplace: Place;
}
export interface People extends Person {
people: Person[]
}
更新:
我已将组件分为以下几部分: 表格
import React from 'react';
import { Person } from '../Person';
import getCounties from '../getCounties';
import { states } from '../states';
const blankPerson: Person = {
id: 0,
firstName: '',
middleName: '',
lastName: '',
birthYear: 0,
birthMonth: 0,
birthDay: 0,
birthState: '',
birthCounty: '',
birthTown: ''
}
interface Props {
onSave: (person: Person) => void
}
export function Form({ onSave }: Props) {
const [person, setPerson] = React.useState(blankPerson);
return <>
<form onSubmit={() => onSave(person)}>
<div>
<input
required
value={person.firstName}
placeholder='first name'
id='firstName'
name='firstName'
onChange={e => setPerson({ ...person, firstName: e.target.value })}
/>
<input
value={person.middleName}
placeholder='middle name'
id='middleName'
name='middleName'
onChange={e => setPerson({ ...person, middleName: e.target.value })}
/>
<input
required
value={person.lastName}
placeholder="last name"
onChange={e => setPerson({ ...person, lastName: e.target.value })}
/>
</div>
<div>
<label htmlFor="birthDay">day of birth</label>
<input
value={person.birthDay}
name="birthDay"
id="birthDay"
type='number'
min='1'
max='31'
onChange={e => setPerson({ ...person, birthDay: e.target.valueAsNumber })}
/>
<label htmlFor='birthMonth'>month of birth</label>
<input
value={person.birthMonth}
name='birthMonth'
id='birthMonth'
min='1'
max='12'
onChange={e => setPerson({ ...person, birthMonth: e.target.valueAsNumber })}
/>
<label htmlFor='birthYear'>year of birth</label>
<input
name='birthYear'
id='birthYear'
type='number'
value={person.birthYear}
onChange={e => setPerson({ ...person, birthYear: e.target.valueAsNumber })}
/>
</div>
<div>
<label>state of birth</label>
<select
value={person.birthState}
placeholder='state of birth'
onChange={e => setPerson({ ...person, birthState: e.target.value })}>
{states.map(state =>
<option key={state} value={state}>
{state}
</option>
)}
</select>
<label>county of birth</label>
<select
value={person.birthCounty}
placeholder='county of birth'
onChange={e => setPerson({ ...person, birthCounty: e.target.value })}>
{getCounties(person.birthState)}
</select>
<label>town or city of birth</label>
<input
value={person.birthTown}
placeholder='town or city of birth'
onChange={e => setPerson({ ...person, birthTown: e.target.value })}
/>
</div>
<button>submit</button>
</form>
</>
}
表格
import React from 'react';
import { Person } from '../Person';
interface Props {
people: Person[]
}
export function Table({people}: Props) {
return <table>{ people.map(person => <tr>
<td>{person.id}</td>
<td>{person.firstName}</td>
<td>{person.middleName}</td>
<td>{person.lastName}</td>
<td>{person.birthDay}</td>
<td>{person.birthMonth}</td>
<td>{person.birthYear}</td>
<td>{person.birthTown}</td>
<td>{person.birthCounty}</td>
<td>{person.birthState}</td>
</tr>)}</table>
}
应用程序将它们捆绑在一起:
import React from 'react';
import './App.css';
import { Person } from './Person';
import {Form} from './Form/Form';
import {Table} from './Table/Table';
function App() {
const [people, setPeople] = React.useState<Person[]>([])
function addPerson(person: Person) {
setPeople([...people, person])
}
return (
<div className="App">
<h1><code>Kyle's Genealogy Thing</code></h1>
<Form onSave={addPerson}/>
<Table people={people}/>
</div>
);
}
export default App;
但现在表格没有更新。
答案 0 :(得分:1)
所以你在这里以三个主要组成部分结束。
首先,如果您将一个人建模为自己的界面会容易得多。你会经常使用它。类似的东西:
export interface Person {
id: number
firstName: string
middleName: string
lastName: string
// etc...
}
现在你可以让一个表单组件接受一个函数作为一个 prop。此函数接受整个 Person
对象作为参数。这个表单组件并不关心这个函数做什么。它需要做的就是与完成它的人一起调用它。由父组件来提供这个功能。
interface Props {
onSave: (person: Person) => void
}
const blankPerson: Person = {
id: 0,
firstName: '',
middleName: '',
lastName: '',
// etc...
}
export function MyForm({ onSave }: Props) {
const [person, setPerson] = React.useState(blankPerson);
return <>
{/* ... */}
<form onSubmit={() => onSave(person)}>
<input
required
value={person.firstName}
placeholder='first name'
id='firstName'
name='firstName'
onChange={e => setPerson({ ...person, firstName: e.target.value })}
/>
</form>
</>
}
注意现在代替:
setFirstName(e.target.value)
你这样做:
setPerson({ ...person, firstName: e.target.value })
设置字段有点麻烦,但少很多状态实例是值得的。
现在表,这个很容易。它甚至不需要状态,只需要道具。
interface Props {
people: Person[]
}
export function MyTable({ people }: Props) {
return <table>{ people.map(person => <tr>...</tr> }</table>
}
最后是将它们联系在一起的父级。
您可以在此处保存人员列表。目标是提供让表单添加人员所需的管道(通过 setPeople
),并将当前人员列表提供到表中(通过 people
)。
换句话说,你的表单是你状态的“setter”,而表是同一状态的只读数据。
function EditablePeopleList() {
const [people, setPeople] = useState<Person[]>([])
function addPerson(person: Person) {
setPeople([...people, person])
}
return (
<div>
<MyForm onSave={addPerson} />
<MyTable people={people} />
<div>
)
}
重点是尽可能保持状态本地化。表格不需要知道表格的状态,表格也不需要知道表格的状态。但是有一个父组件提供数据和函数来将 people
作为道具更新到它的子组件。
答案 1 :(得分:0)
像这样在你的表格组件中将人们状态作为道具传递。
您的单独表格组件:
const Table = (props) => {
const {people} = props;
const renderHeader = () => {
let columns = [
'id',
'firstName',
'middleName',
'lastName',
'birthDay',
'birthMonth',
'birthYear',
'birthState',
'birthCounty',
'birthTown'
]
if (people.length === 0) {
return <h3>add people to the array to view table</h3>
} else if (people.length > 0) {
return columns.map((col: string, index: number) => {
return <th key={index}>{col.toUpperCase()}</th>
});
}
}
const renderBody = () => {
return people.map(({
id,
firstName,
middleName,
lastName,
birthDay,
birthMonth,
birthYear,
birthState,
birthCounty,
birthTown
}) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{firstName}</td>
<td>{middleName}</td>
<td>{lastName}</td>
<td>{birthDay}</td>
<td>{birthMonth}</td>
<td>{birthYear}</td>
<td>{birthTown}</td>
<td>{birthCounty}</td>
<td>{birthState}</td>
</tr>
);
});
}
return <table id="people">
<thead>
<tr>{renderHeader()}</tr>
</thead>
<tbody>
{renderBody()}
</tbody>
</table>
}
然后在你的主要组件中导入你的新表格组件:
<Table people={people} />