0

I started working on my engineering thesis and decided to write it as SPA in React that communicates with REST API on a ASP.NET Core backend. So far I have done a couple of apps using ASP.NET MVC and Winforms, but I wanted to broaden my knowledge and learn some new technologies. Therefore I started learning React recently and in the beginning I was trying to create really simple SPA in it.

Here is the problem: Let's suppose that we have an app with universities' data. That is: Universities, their departments, departments' subjects, subjects' lecturers, etc.

I'd like to have a simple navigation through the above structure - on the main page display every university that I have in a database, then I'd like to be able to click on a university and get it's departments, then on departments list click on one department and get for example subjects from that department, and so on, you get the idea..

My backend with necessary endpoints is running on localhost. 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.

I've spent 3 days doing it and tried everything but unfortunately with no effect, and now I have such a mess in my head that I consider going back to good old ASP.NET MVC.. But I'm sure there must be something I'm missing and don't understand because I don't believe it's not possible.. I think I could also have many habits from MVC that might affect my understanding of web apis and pure frontent apps.

I've read official documentation, watched tutorials, stackoverflowed, tried my own ideas, repeated every step 5 times. Simple routing and overall react workflow are not a problem for me, the problem is that specific scenario.

Could anyone provide me some information or clues how to deal with such a design in React (ideally with examples)?


EDIT

Ok, so I'm sharing the design I came up with today. This works as expected but there's no possibility to go to a specific route manually, by entering it in browser's searchbox - the only way is to go down through the whole "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

And finally - 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

As all this is very repetitive while we start going down deeper in the university path, I think it would be nice to flatten those lists in one List component (with maybe some specific properties in case I want to display some more things) and only pass fetched elements to it. Almost whole app uses that "list like" gui so it could be useful. That's the case I will be working on now.

Now when you see what design I had in my mind feel free to share your thoughts about it. Maybe I should have it done in some other, better way?


EDIT 2

Updated code, added breadcrumbs! Cool, but there's a big problem that I mentioned earlier - I can't get directly to specific route, therefore I can't go back from lessons to departments... So the whole Router thing is useless, especially when I want to share links to specific routes (in the future). Anyway here is an updated code.

newbie
  • 200
  • 3
  • 6
  • I'd strongly suggest that you provide code samples of what you've tried in React.js in order to help others point out easily and accurately what went wrong in your implementation. – Michael Fayad Oct 17 '18 at 21:30

1 Answers1

0

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.

Typically, you would use a state container library for this. The most commonly used with React is 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 middleware to dispatch actions for async calls/requests.

A good video tutorial that explains this in depth is: https://www.udemy.com/react-redux/

Paras
  • 8,266
  • 24
  • 49
  • I thought that this whole Redux thing would be an overkill for such a trivial design, but according to your suggestion I checked it out and it seems that this might be the solution I'm looking for. Thank you. I leave the question open for one more day in case someone come up with a pure React solution. – newbie Oct 18 '18 at 11:26