使用 React 路由器进行简单导航 [出错]
Simple navigation with react router [gone wrong]
我开始研究我的工程论文,并决定将其编写为 React 中的 SPA,它与 ASP.NET 核心后端上的 REST API 通信。到目前为止,我已经使用 ASP.NET MVC 和 Winforms 完成了几个应用程序,但我想扩展我的知识并学习一些新技术。因此,我最近开始学习 React,一开始我试图在其中创建非常简单的 SPA。
问题来了:
假设我们有一个包含大学数据的应用程序。即:大学、院系、院系学科、学科讲师等
我希望通过上述结构进行简单导航 - 在主页上显示我在数据库中拥有的每所大学,然后我希望能够点击一所大学并获得它的院系, 然后在部门列表上单击一个部门并从该部门获取例如主题,等等,你明白了..
我的具有必要端点的后端是 运行 在本地主机上。问题是何时何地在前端获取数据,如何在组件之间传递 id,如何为此类应用程序构建结构等。
我已经花了 3 天时间做这件事并尝试了所有方法,但不幸的是没有任何效果,现在我脑子里一片混乱,我考虑回到旧的 ASP.NET MVC..但是我我确定一定有什么东西是我遗漏和不明白的,因为我不相信这是不可能的。
我想我也可能有很多来自 MVC 的习惯,这些习惯可能会影响我对 web api 和纯前端应用程序的理解。
看了官方文档,看了教程,Whosebug,尝试了自己的想法,每一步重复5次。简单的路由和整体的反应工作流对我来说不是问题,问题是具体的场景。
谁能给我一些信息或线索,说明如何在 React 中处理这样的设计(最好有示例)?
编辑
好的,所以我要分享我今天想出的设计。这按预期工作,但不可能通过在浏览器的搜索框中输入它来手动转到特定路线 - 唯一的方法是通过整个 "university path"
App.js
const App = () =>
<BrowserRouter>
<>
<NavBar />
<div className="row home-container">
<div className="col s12 m8 l9 home-part">
<div className="data-container">
<Route path="/" component={MainContainer} />
</div>
</div>
<Sidebar />
</div>
</>
</BrowserRouter>
export default App
MainContainer.js
const defaultBreadcrumb = { title: "Uczelnie", path: "/universities" };
class MainContainer extends React.Component {
state = {
elements: [],
breadcrumbs: [
defaultBreadcrumb
]
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/universities`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
componentWillReceiveProps(nextProps){
if(nextProps){
var newBreadcrumbs = nextProps.location.breadcrumbs ? nextProps.location.breadcrumbs : [defaultBreadcrumb];
this.setState({
breadcrumbs: newBreadcrumbs
});
}
}
render() {
return (
<>
<nav className="colornav">
<div className="nav-wrapper path-header-wrapper">
<div className="col s12 subsite-title">
{this.state.breadcrumbs.map((b, key) => (
<NavLink key={key} to={b.path} className="breadcrumb">{b.title}</NavLink>
))}
</div>
</div>
</nav>
<div className="home-content">
<ul className="collection">
<Route
exact
path="/universities"
render={() => {return <Universities elements={this.state.elements} />}}
/>
<Route
exact
path="/universities/:id"
render={() => { return <Departments {...this.props} />}}
/>
<Route
exact
path="/universities/:id/Lessons"
render={() => { return <Lessons {...this.props} />}}
/>
</ul>
</div>
</>
);
}
}
export default MainContainer
Universities.js
const Universities = ({elements}) =>
<>
{elements.map((u) =>
<NavLink
key={u.name}
to={{
pathname: `/universities/${u.name}`,
univId: u.universityId,
univName: u.name,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: u.name, path: `/universities/${u.universityId}`}
]
}}
className="collection-item path-list-item">
<div>{u.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
export default Universities
Departments.js
class Departments extends React.Component {
state = {
elements: []
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/departmentsofuniversity/${this.props.location.univId}`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
render() {
return (
<>
{this.state.elements.map((d) =>
<NavLink
key={d.name}
to={{
pathname: `/universities/${d.name}/lessons`,
deptId: d.departmentId,
deptName: d.name,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: this.props.location.univName, path: `/universities/${this.props.location.univId}`},
{title: d.name, path: `/universities/${this.props.location.univId}/lessons`}
]
}}
className="collection-item path-list-item">
<div>{d.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
);
}
}
export default Departments
最后 - Lessons.js
class Lessons extends React.Component {
state = {
elements: []
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/lessonsfromdepartment/${this.props.location.deptId}`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
render() {
return (
<>
{this.state.elements.map((l, key) =>
<NavLink
key={key}
to={{
pathname: `/universities/${l.name}/Lessons/${l.name}`,
deptId: l.departmentId,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: this.props.location.univName, path: `/universities/${this.props.location.univId}`},
{title: this.props.location.deptName, path: `/universities/${this.props.location.deptName}/lessons`},
{title: l.name, path: `/universities/${this.props.location.deptId}/lessons/${l.name}`}
]
}}
className="collection-item path-list-item">
<div>{l.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
);
}
}
export default Lessons
当我们开始深入大学学习时,所有这些都是非常重复的,我认为将这些列表扁平化到一个列表组件中会很好(可能有一些特定的属性,以防我想显示更多things) 并且只将获取的元素传递给它。几乎整个应用程序都使用 "list like" gui,因此它可能很有用。这就是我现在要处理的情况。
现在,当您看到我心中的设计时,请随时分享您的想法。也许我应该用其他更好的方式完成它?
编辑 2
更新了代码,添加了面包屑!很酷,但是我之前提到的一个大问题 - 我无法直接到达特定路线,因此我无法从课程返回到部门......所以整个 Router 东西都没用,特别是当我想分享时链接到特定路线(将来)。无论如何,这是更新的代码。
The problem is when and where to fetch the data in frontend, how to
pass id's between components, how to do a structure for such an
application, etc.
通常,您会为此使用状态容器库。 React 最常使用的是 Redux. You would store/cache the response data in the store, fire requests using actions and parse the response in reducers. You can also use redux-promise 中间件,用于为异步调度操作 calls/requests。
深入解释这一点的一个很好的视频教程是:https://www.udemy.com/react-redux/
我开始研究我的工程论文,并决定将其编写为 React 中的 SPA,它与 ASP.NET 核心后端上的 REST API 通信。到目前为止,我已经使用 ASP.NET MVC 和 Winforms 完成了几个应用程序,但我想扩展我的知识并学习一些新技术。因此,我最近开始学习 React,一开始我试图在其中创建非常简单的 SPA。
问题来了: 假设我们有一个包含大学数据的应用程序。即:大学、院系、院系学科、学科讲师等
我希望通过上述结构进行简单导航 - 在主页上显示我在数据库中拥有的每所大学,然后我希望能够点击一所大学并获得它的院系, 然后在部门列表上单击一个部门并从该部门获取例如主题,等等,你明白了..
我的具有必要端点的后端是 运行 在本地主机上。问题是何时何地在前端获取数据,如何在组件之间传递 id,如何为此类应用程序构建结构等。
我已经花了 3 天时间做这件事并尝试了所有方法,但不幸的是没有任何效果,现在我脑子里一片混乱,我考虑回到旧的 ASP.NET MVC..但是我我确定一定有什么东西是我遗漏和不明白的,因为我不相信这是不可能的。 我想我也可能有很多来自 MVC 的习惯,这些习惯可能会影响我对 web api 和纯前端应用程序的理解。
看了官方文档,看了教程,Whosebug,尝试了自己的想法,每一步重复5次。简单的路由和整体的反应工作流对我来说不是问题,问题是具体的场景。
谁能给我一些信息或线索,说明如何在 React 中处理这样的设计(最好有示例)?
编辑
好的,所以我要分享我今天想出的设计。这按预期工作,但不可能通过在浏览器的搜索框中输入它来手动转到特定路线 - 唯一的方法是通过整个 "university path"
App.js
const App = () =>
<BrowserRouter>
<>
<NavBar />
<div className="row home-container">
<div className="col s12 m8 l9 home-part">
<div className="data-container">
<Route path="/" component={MainContainer} />
</div>
</div>
<Sidebar />
</div>
</>
</BrowserRouter>
export default App
MainContainer.js
const defaultBreadcrumb = { title: "Uczelnie", path: "/universities" };
class MainContainer extends React.Component {
state = {
elements: [],
breadcrumbs: [
defaultBreadcrumb
]
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/universities`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
componentWillReceiveProps(nextProps){
if(nextProps){
var newBreadcrumbs = nextProps.location.breadcrumbs ? nextProps.location.breadcrumbs : [defaultBreadcrumb];
this.setState({
breadcrumbs: newBreadcrumbs
});
}
}
render() {
return (
<>
<nav className="colornav">
<div className="nav-wrapper path-header-wrapper">
<div className="col s12 subsite-title">
{this.state.breadcrumbs.map((b, key) => (
<NavLink key={key} to={b.path} className="breadcrumb">{b.title}</NavLink>
))}
</div>
</div>
</nav>
<div className="home-content">
<ul className="collection">
<Route
exact
path="/universities"
render={() => {return <Universities elements={this.state.elements} />}}
/>
<Route
exact
path="/universities/:id"
render={() => { return <Departments {...this.props} />}}
/>
<Route
exact
path="/universities/:id/Lessons"
render={() => { return <Lessons {...this.props} />}}
/>
</ul>
</div>
</>
);
}
}
export default MainContainer
Universities.js
const Universities = ({elements}) =>
<>
{elements.map((u) =>
<NavLink
key={u.name}
to={{
pathname: `/universities/${u.name}`,
univId: u.universityId,
univName: u.name,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: u.name, path: `/universities/${u.universityId}`}
]
}}
className="collection-item path-list-item">
<div>{u.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
export default Universities
Departments.js
class Departments extends React.Component {
state = {
elements: []
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/departmentsofuniversity/${this.props.location.univId}`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
render() {
return (
<>
{this.state.elements.map((d) =>
<NavLink
key={d.name}
to={{
pathname: `/universities/${d.name}/lessons`,
deptId: d.departmentId,
deptName: d.name,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: this.props.location.univName, path: `/universities/${this.props.location.univId}`},
{title: d.name, path: `/universities/${this.props.location.univId}/lessons`}
]
}}
className="collection-item path-list-item">
<div>{d.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
);
}
}
export default Departments
最后 - Lessons.js
class Lessons extends React.Component {
state = {
elements: []
}
componentDidMount() {
fetch(`https://localhost:44349/api/v1/lessonsfromdepartment/${this.props.location.deptId}`)
.then(res => res.json())
.then(json => this.setState({elements: json}));
}
render() {
return (
<>
{this.state.elements.map((l, key) =>
<NavLink
key={key}
to={{
pathname: `/universities/${l.name}/Lessons/${l.name}`,
deptId: l.departmentId,
breadcrumbs: [
{title: "Uczelnie", path: `/universities`},
{title: this.props.location.univName, path: `/universities/${this.props.location.univId}`},
{title: this.props.location.deptName, path: `/universities/${this.props.location.deptName}/lessons`},
{title: l.name, path: `/universities/${this.props.location.deptId}/lessons/${l.name}`}
]
}}
className="collection-item path-list-item">
<div>{l.name}
<li className="secondary-content">
<i className="material-icons">send</i>
</li>
</div>
</NavLink>
)}
</>
);
}
}
export default Lessons
当我们开始深入大学学习时,所有这些都是非常重复的,我认为将这些列表扁平化到一个列表组件中会很好(可能有一些特定的属性,以防我想显示更多things) 并且只将获取的元素传递给它。几乎整个应用程序都使用 "list like" gui,因此它可能很有用。这就是我现在要处理的情况。
现在,当您看到我心中的设计时,请随时分享您的想法。也许我应该用其他更好的方式完成它?
编辑 2
更新了代码,添加了面包屑!很酷,但是我之前提到的一个大问题 - 我无法直接到达特定路线,因此我无法从课程返回到部门......所以整个 Router 东西都没用,特别是当我想分享时链接到特定路线(将来)。无论如何,这是更新的代码。
The problem is when and where to fetch the data in frontend, how to pass id's between components, how to do a structure for such an application, etc.
通常,您会为此使用状态容器库。 React 最常使用的是 Redux. You would store/cache the response data in the store, fire requests using actions and parse the response in reducers. You can also use redux-promise 中间件,用于为异步调度操作 calls/requests。
深入解释这一点的一个很好的视频教程是:https://www.udemy.com/react-redux/