嗨,我正在尝试使用React.Js和打字稿制作一个简单的CRUD示例...
我具有以下组件层次结构:
-FetchNaselje
--Modal
---AddNaselje
AddNaselje是Modal的子代,而Modal是FetchNaselje的子代,我试图每次有人从AddNaselje提交/保存 form 时重新渲染或强制更新FetchNaselje,但我很难过这样做。
我厌倦了传递父母的历史并将其称为孩子,例如:this.props.history.push(“ / fetchnaselje”);但什么也没发生
这是我的route.tsx文件:
import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchNaselje } from './components/FetchNaselje';
import { AddNaselje } from './components/AddNaselje';
export const routes = <Layout>
<Route exact path='/' component={Home} />
<Route path='/fetchnaselje' component={FetchNaselje} />
<Route path='/addnaselje(/:nasid)' component={AddNaselje} />
<Route path='/naselje/edit(/:nasid)' component={AddNaselje} />
</Layout>;
这是我的父组件代码:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
import { AddNaselje } from './AddNaselje';
import { Modal } from './Modal/Modal';
interface FetchNaseljeDataState {
nasList: NaseljeData[];
loading: boolean;
showModal: boolean
nas_id: number;
}
export class FetchNaselje extends React.Component<RouteComponentProps<{}>, FetchNaseljeDataState> {
constructor() {
super();
this.state = { nasList: [], loading: true, showModal: false, nas_id: -1 };
fetch('api/Naselje/Index')
.then(response => response.json() as Promise<NaseljeData[]>)
.then(data => {
this.setState({ nasList: data, loading: false });
});
// This binding is necessary to make "this" work in the callback
this.handleDelete = this.handleDelete.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderNaseljeTable(this.state.nasList);
return <div>
<h1>Naselje Data</h1>
<div>This component demonstrates fetching Naselje data from the server.</div>
<div>
<Link to="/addnaselje">Create New</Link><br /><br />
<button type="button" onClick={this.showModal} className="btn">
Show Modal
</button>
<Modal
show={this.state.showModal}>
<AddNaselje history={this.props.history} parent={this} />
</Modal>
</div>
{contents}
</div>;
}
showModal = () => {
this.setState({
... this.state,
showModal: !this.state.showModal
});
this.forceUpdate();
};
// Handle Delete request for an naselje
private handleDelete(id: number) {
if (!confirm("Do you want to delete naselje with Id: " + id))
return;
else {
fetch('api/Naselje/Delete/' + id, {
method: 'delete'
}).then(data => {
this.setState(
{
nasList: this.state.nasList.filter((rec) => {
return (rec.idnaselje != id);
})
});
});
}
}
private handleEdit(id: number) {
//this.props.history.push("/naselje/edit/" + id);
}
// Returns the HTML table to the render() method.
private renderNaseljeTable(naseljeList: NaseljeData[]) {
return <table className='table'>
<thead>
<tr>
<th></th>
<th>ID Naselje</th>
<th>Naziv</th>
<th>Postanski Broj</th>
<th>Drzava</th>
</tr>
</thead>
<tbody>
{naseljeList.map(nas =>
<tr key={nas.idnaselje}>
<td></td>
<td>{nas.idnaselje}</td>
<td>{nas.naziv}</td>
<td>{nas.postanskiBroj}</td>
<td>{nas.drzava && nas.drzava.naziv}</td>
<td>
<a className="action" onClick={(id) => this.handleEdit(nas.idnaselje)}>Edit</a> |
<a className="action" onClick={(id) => this.handleDelete(nas.idnaselje)}>Delete</a>
</td>
</tr>
)}
</tbody>
</table>;
}
}
export class NaseljeData {
idnaselje: number = 0;
naziv: string = "";
postanskiBroj: string = "";
drzava: DrzavaData = { iddrzava: 0, naziv: ""};
drzavaid: number = 0;
}
export class DrzavaData {
iddrzava: number = 0;
naziv: string = "";
}
我的模态组件就像包装器,其样式设置为显示模态窗口:
import * as React from 'react';
const style = require('./style.css');
interface ModaleDataState {
show: boolean;
}
export class Modal extends React.Component<any, ModaleDataState> {
render() {
if (!this.props.show) {
return null;
}
return <div className="modal-background">
<div className="modal-main">
{this.props.children}
</div>
</div>
}
}
最后是子组件:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
import { NaseljeData } from './FetchNaselje';
import { DrzavaData } from './FetchNaselje';
interface AddNaseljeDataState {
title: string;
loading: boolean;
drzavaList: Array<any>;
nasData: NaseljeData;
drzavaId: number;
}
export class AddNaselje extends React.Component<any, AddNaseljeDataState> {
constructor(props) {
super(props);
this.state = { title: "", loading: true, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
fetch('api/Naselje/GetDrzavaList')
.then(response => response.json() as Promise<Array<any>>)
.then(data => {
this.setState({ drzavaList: data });
});
var nasid = -1;
if (this.props.match) {
nasid = this.props.match.params["nasid"];
}
// This will set state for Edit naselje
if (nasid > 0) {
fetch('api/Naselje/Details/' + nasid)
.then(response => response.json() as Promise<NaseljeData>)
.then(data => {
this.setState({ title: "Edit", loading: false, nasData: data });
});
}
// This will set state for Add naselje
else {
this.state = { title: "Create", loading: false, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
}
// This binding is necessary to make "this" work in the callback
this.handleSave = this.handleSave.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderCreateForm(this.state.drzavaList);
return <div>
<h1>{this.state.title}</h1>
<h3>Naselje</h3>
<hr />
{contents}
</div>;
}
// This will handle the submit form event.
private handleSave(event) {
event.preventDefault();
const data = new FormData(event.target);
// PUT request for Edit naselje.
if (this.state.nasData.idnaselje) {
fetch('api/Naselje/Edit', {
method: 'PUT',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
// POST request for Add naselje.
else {
fetch('api/Naselje/Create', {
method: 'POST',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
this.props.parent.showModal();
window.location.reload()
}
// This will handle Cancel button click event.
private handleCancel(e) {
e.preventDefault();
//this.props.parent.showModal();
this.props.history.push("/fetchnaselje");
//this.props.parent.forceUpdate();
}
// Returns the HTML Form to the render() method.
private renderCreateForm(drzavaList: Array<any>) {
return (
<form onSubmit={this.handleSave} >
<div className="form-group row" >
<input type="hidden" name="idnaselje" value={this.state.nasData.idnaselje} />
</div>
< div className="form-group row" >
<label className=" control-label col-md-12" htmlFor="Naziv">Naziv</label>
<div className="col-md-4">
<input className="form-control" type="text" name="naziv" defaultValue={this.state.nasData.naziv} required />
</div>
</div >
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="PostanskiBroj" >Postanski broj</label>
<div className="col-md-4">
<input className="form-control" name="PostanskiBroj" defaultValue={this.state.nasData.postanskiBroj} required />
</div>
</div>
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="Drzava">Država</label>
<div className="col-md-4">
<select className="form-control" data-val="true" name="drzavaid" defaultValue={this.state.nasData.drzava ? this.state.nasData.drzava.naziv : ""} required>
<option value="">-- Odaberite Državu --</option>
{drzavaList.map(drzava =>
<option key={drzava.iddrzava} value={drzava.iddrzava}>{drzava.naziv}</option>
)}
</select>
</div>
</div >
<div className="form-group">
<button type="submit" className="btn btn-default">Save</button>
<button className="btn" onClick={this.handleCancel}>Cancel</button>
</div >
</form >
)
}
}
此道具历史记录推送不会引发任何错误,但不会重新呈现我的父组件。
我不确定这里最好的方法是什么...请考虑一下我没有太多的反应经验,因此,如果您尝试以完整的方式而不是一小段时间来解释最佳方法,我将不胜感激。回答...谢谢!
答案 0 :(得分:1)
React中我最喜欢的重新路由方法是利用react-router-dom功能(我看到您已经在使用该模块)。以下是一个简单的示例(以JS为例,但您会明白的):
import React, { Fragment } from 'react;
import { Redirect } from 'react-router-dom';
class ReRoute extends React.Component {
state = {
...yourState,
sendToNextPage: false
}
sendToNext = () => this.setState({ sendToNextPage: true })
render() {
return (
<Fragment>
<h1>Your Content....</h1>
<button onClick={this.sendToNext}>Button to navigate</button>
{this.state.sendToNextPage &&
<Redirect to='/path-to-next-page' />
}
</Fragment>
)
}
}
React中的虚拟路由周围有很多选项,但是上面是我最喜欢的,因为有多种方法可以将组件返回到渲染中,这将提示重定向。对我来说-通过布尔值将状态控制在状态中(对于您自己和他人)非常清楚触发重定向的原因,并且我是重定向组件的其他功能的支持者(请参阅this)< / p>