reactjs - React Redux, jak řešit vytváření položek formuláře a přesměrování?
Jsem nový v Reactu (a Reduxu) a snažím se vytvořit jednoduchý formulář, který vytvoří Položku (název, typ) a po vytvoření přesměruje na stránku ListItems.
Používám react-thunk pro zpracování asynchronních akcí a všechno je v TypeScriptu.
Můj problém je, jak mám řešit výsledky vytváření a přesměrování? Protože má akce CreateItemRequest je asynchronní, jak mohu informovat své kontejnery, že položka byla úspěšně vytvořena, aby se přesměrovaly na stránku ListItems.
Zkoušel jsem jednoduše použít boolean ve své akci CreateItemSuccess v mém reduceru, ale pak nemohu přejít na samotný formulář vytvoření, protože boolean je nyní v modelu true, a okamžitě přesměruje na stránku ListIems.
Jsem tady zaseknutý, jsem si jistý, že něco hloupého přehlížím, ale nemůžu nikde nic najít...
Má komponenta:
import { Route, Redirect } from "react-router-dom";
import { connect, Dispatch } from 'react-redux';
import * as React from 'react';
import * as Types from '../../types';
import * as Actions from '../../actions';
interface ICreateModelDispatchProps {
LoadItems: () => void;
ChangeForm: (model: Actions.IItemCreateModel) => void;
CreateItem: (model: Actions.IItemCreateModel) => void;
}
interface ICreateItemStateProps {
Types: Types.ITypeEntity[];
ItemCreated: boolean;
Model: Actions.IItemCreateModel;
}
class CreateItem extends React.Component<ICreateItemStateProps & ICreateModelDispatchProps, Types.IAppState> {
public componentDidMount() {
this.props.LoadItems();
}
public render() {
if (this.props.ItemCreated) {
const redirect = () => <Redirect to={{ pathname: '/items' }} />;
return <Route render={redirect} />;
}
if (!this.props.Types.length) {
return <div id="create-item" className="loading" />;
}
const { Name, Type } = this.props.Model;
const onSubmit = this.onSubmit.bind(this);
const onNameChange = this.onNameChange.bind(this);
const onTypeChange = this.onTypeChange.bind(this);
return (
<div id="create-item">
<form onSubmit={onSubmit}>
<div>
<label htmlFor="name">Name</label>
<input type="text" id="name" value={Name} placeholder="Item's Name" onChange={onNameChange} />
</div>
<div>
<label htmlFor="type">Type</label>
<select id="type" onChange={onTypeChange} value={Type}>
<option value="-1">Choose a type</option>
{this.props.Types.map(type => <option key={type.Id} value={type.Id}>{type.Name}</option>)}
</select>
</div>
<div>
<input type="submit" value="CREATE" />
</div>
</form>
</div>
)
}
private onNameChange(event: React.ChangeEvent<HTMLInputElement>) {
this.props.ChangeForm(Object.assign(this.props.Model, { Name: event.target.value }));
}
private onTypeChange(event: React.ChangeEvent<HTMLSelectElement>) {
this.props.ChangeForm(Object.assign(this.props.Model, { Type: event.target.value }));
}
private onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
this.props.CreateItem(this.props.Model);
}
}
export function mapStateToProps(state: Types.IAppState): ICreateItemStateProps {
const types = Object.keys(state.Entities.Types).map(key => state.Entities.Types[Number(key)]);
const Model = state.CreateItem;
return {
Model,
Types: types,
ItemCreated: !!state.CreateItem.Created,
};
}
export function mapDispatchToProps(dispatch: Dispatch): ICreateModelDispatchProps {
return {
LoadItems: () => dispatch(Actions.ITEM_TYPES_REQUEST()),
ChangeForm: (model) => dispatch(Actions.ITEM_CREATE_CHANGE(model)),
CreateItem: (model) => dispatch(Actions.ITEM_CREATE_REQUEST(model)),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(CreateItem);
Odpověď č. 1
Svou akci můžete napsat pomocí Promise nebo async/await. Zde je příklad v JS (ne TS)
export default function ITEM_CREATE_REQUEST(model) {
return (dispatch) => {
return new Promise((resolve, reject) => {
/* SOME STUFF */
resolve(SOME_DATA);
});
}
};
pak ji můžete použít k navigaci, když je vyřešena
onSubmit() {
event.preventDefault();
this.props.CreateItem(this.props.Model).then((SOME_DATA) => {
/* PERFORM REDIRECT */
});
}
Odpověď č. 2
Když spustíte svou asynchronní akci, aktualizujete stav úložiště v nějakém nepředvídatelném čase v budoucnu. Vaše komponenta musí tyto aktualizace přijímat nějak přes mapStateToProps.
Tímto způsobem byste mohli zajistit, že se aktualizovaly vlastnosti pro vytvoření nové položky - pravděpodobně nejlépe uvnitř životního cyklu getSnapshotBeforeUpdate:
getSnapshotBeforeUpdate(prevProps, prevState) {
if (prevProps.itemCreated !== this.props.itemCreated) {
// itemCreated could be a counter or something else.
// For example, you count up after item is created.
// Whenever that prop changes, you navigate away like this.
const { history } = this.props
history.pushState(null, '/anywhere') or
history.replaceState(null, '/anywhere')
}
return null;
}
Zde jsou dokumenty pro getSnapshotBeforeUpdate.
