我想在 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 });
}
}
ExamplesTabs.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 - 指南
我有一个具有相同方法的多步骤形式的沙箱项目,mb它与您想要的类似: https://github.com/AleksK1NG/React-meetuper/blob/master/client/src/components/MeetupCreate/MeetupCreateWizard/MeetupCreateWizard.js (MeetupCreate文件夹是多步骤形式)
希望您理解多步骤表单功能的主要思想:)
关于javascript - React 中的多步骤形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57231082/