我想在Microsoft UI Fabric的支持下在React中创建一个多步骤表单。
像这样:
因此,我想创建一个动态的多步骤表单,其中内部组件完全彼此独立(除非存在一些明确的依赖关系)。
我想完成这样的事情:
public render(): React.ReactElement<MyComponentProps> {
const list = [
{ headerText: 'Personal Details', component: <PersonalDetailsTab /> },
{ headerText: 'Company details', component: <CompanyDetailsTab /> },
{ headerText: 'Other', component: <OtherTab /> }
];
return (
<MultiStepForm steps={list} ></MultiStepForm>
);
}
这将是美好的。
请注意,其中的三个组件彼此不认识。
此外:
国家管理
UI再现
验证方式
...是完全独立的
但是,当我要管理组件之间的状态和验证时,我当然会遇到问题。
主要是:
当我单击选项卡上的“下一个”按钮并转到下一个选项卡,然后又想通过单击“上一步”按钮返回到上一个选项卡时,我丢失了先前填充的字段的数据。
下一个选项卡也必须能够依赖在上一个选项卡中输入的数据(例如,在第三个选项卡中,称为传递姓氏和公司ID的服务)。我想这样就不会失去独立性和脱钩性。
当我从选项卡单击NEXT并转到下一个选项卡时,我认为应该有一种机制,该状态必须遵守某些约束条件(愚蠢的示例:第二个选项卡不接受以前用“ Rossi”命名的任何人)姓...第二个标签(或第一个标签?)应显示验证错误)。
遗憾的是我不是React专家。可能我不想使用Redux或其他框架。
这是我的解决方案:
MyComponents.tsx:
export default class MyComponent extends React.Component<MyComponent> {
constructor(props: MyComponent) {
super(props);
this.state = {};
}
public render(): React.ReactElement<MyComponentProps> {
const list = [
{ headerText: 'Personal Details', component: <PersonalDetailsTab /> },
{ headerText: 'Company details', component: <CompanyDetailsTab /> },
{ headerText: 'Other', component: <OtherTab /> }
];
return (
<MultiStepForm steps={list} ></MultiStepForm>
);
}
}
MultiStepForm.tsx:
import * as React from 'react';
import { Pivot, PivotItem, PivotLinkSize, PivotLinkFormat } from 'office-ui-fabric-react';
import { StepTab } from '../StepTab';
interface IMultiStepFormProps {
steps: any[];
}
interface IMultiStepFormState {
steps: any;
stepsCount: number;
selectedKey: number;
}
export class MultiStepForm extends React.Component<IMultiStepFormProps, IMultiStepFormState> {
constructor(props: IMultiStepFormProps) {
super(props);
this._handleBackClick = this._handleBackClick.bind(this);
this._handleNextClick = this._handleNextClick.bind(this);
this._onLinkClick = this._onLinkClick.bind(this);
this._updateComponent = this._updateComponent.bind(this);
this.state = {
selectedKey: 0,
steps: props.steps,
stepsCount: props.steps.length
};
}
public render(): React.ReactElement<IMultiStepFormProps> {
return (
<Pivot linkSize={PivotLinkSize.large} linkFormat={PivotLinkFormat.tabs}
selectedKey={`${this.state.selectedKey}`}
onLinkClick={this._onLinkClick} >
{this.state.steps.map((s, i) =>
<PivotItem headerText={s.headerText} itemKey={`${i}`} >
<StepTab
component={s.component} componentState={s.childrenState}
_handleBackClick={this._handleBackClick}
_handleNextClick={this._handleNextClick}
_updateComponent={this._updateComponent}
/>
</PivotItem>)}
</Pivot>
);
}
private _updateComponent(comp, compState) {
// work in progress...
var s = this.state.steps;
s[this.state.selectedKey].component = comp;
s[this.state.selectedKey].childrenState = compState;
this.setState({
steps: s
});
}
private _handleBackClick(): void {
let currentIndex = this.state.selectedKey;
let count = this.state.stepsCount;
let newIndex = ((currentIndex - 1) + count) % count;
this.setState({
selectedKey: newIndex
});
}
private _handleNextClick(): void {
let currentIndex = this.state.selectedKey;
let count = this.state.stepsCount;
let newIndex = (currentIndex + 1) % count;
this.setState({
selectedKey: newIndex
});
}
private _onLinkClick(item: PivotItem): void {
let newIndex = parseInt(item.props.itemKey);
this.setState({
selectedKey: newIndex
});
}
}
StepTab.tsx:
import * as React from 'react';
import { PrimaryButton } from 'office-ui-fabric-react';
export interface IStepProps {
component: React.Component;
componentState?: any;
_handleBackClick: () => void;
_handleNextClick: () => void;
_updateComponent: (comp: any, compState: any) => void;
}
export interface IStepState {
componentState: React.Component;
// _getComponentState: (x, y) => void;
}
export class StepTab extends React.Component<IStepProps, IStepState> {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
componentState: this.props.componentState || {},
// _getComponentState: this.props._updateComponent
};
}
public componentDidMount() {
console.log("StepTab MOUNT");
if (this.state.componentState) {
// work in progress
}
}
public render(): React.ReactElement<IStepProps> {
return (
<form onSubmit={this._onSubmit.bind(this)} onChange={this.handleInputChange} >
{this.props.component}
<div style={{ textAlign: "right" }}>
<PrimaryButton text="BACK" onClick={(this._onBack.bind(this))} allowDisabledFocus={true} />
<PrimaryButton text="NEXT" type="submit"
allowDisabledFocus={true} />
</div>
</form>
);
}
public _onBack(e) {
e.preventDefault();
this.props._handleBackClick();
}
public _onSubmit(e) {
e.preventDefault();
this.props._updateComponent(this.props.component, this.state.componentState);
this.props._handleNextClick();
}
public handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name || target.id;
var partialState = this.state.componentState;
partialState[name] = value;
this.setState({ componentState: partialState });
}
}
示例Tabs.tsx:
import * as React from 'react';
import {
TextField, ITextFieldProps, Stack, IconButton, ComboBox, Label, MaskedTextField,
Rating, IComboBoxOption, SelectableOptionMenuItemType, getId
} from 'office-ui-fabric-react';
export class PersonalDetailsTab extends React.Component<{}, {}> {
public render(): React.ReactElement<{}> {
return (<>
<TextField name="name" label="Name"></TextField>
<TextField name="surname" label="Surname"></TextField>
{/* checkbox */}
</>);
}
}
export class CompanyDetailsTab extends React.Component<{}, {}> {
public render(): React.ReactElement<{}> {
return (<>
<TextField name="companyId" label="Company id" ></TextField>
<TextField name="companyName" label="Company Name"></TextField>
</>);
}
}
export class OtherTab extends React.Component<{}, {}> {
public render(): React.ReactElement<{}> {
return (<>
{/* bla bla */}
</>);
}
}
如果有人提出建议或有效的替代方法:)
最佳答案
这是Brad https://github.com/bradtraversy/react_step_form的好例子,
https://www.youtube.com/watch?v=zT62eVxShsY-指南
我有一个沙箱项目,采用了多步表单,使用了相同的方法,但它与您想要的类似:
https://github.com/AleksK1NG/React-meetuper/blob/master/client/src/components/MeetupCreate/MeetupCreateWizard/MeetupCreateWizard.js(MeetupCreate文件夹是多步骤表单)
希望您了解多步骤表单功能的主要思想:)