简体   繁体   中英

How to proper split React application components

I am learning React by creating an application, but I think I underestimated its complexity. Let me share with you to know if I got it right:

The idea is to create a React App to track the subjects I want to study. I've created the following structure:

MainTopic:
-- title: String
-- percentage_completed: Number
-- Topic: Array
---- Subtopic: Array
---- title: String
---- percentage_completed: Number
------ Resources: Array
------ title: String
------ link: String
------ completed: Boolean

The JSON structure should look like this - the documents are tighed up by the _id of his parent:

{
    "title": String,
    "percentage_completed": Number
    "topic":[
    {
        "title":String,
        "percentage_completed":Number
        "subtopic":[
        {
            "title":String
            "percentage_completed": Number
            "resources":[
            {
                "title":String
                "link": String
                "concluded": Boolean
            }
            ]
        }
        ]
    }
    ]
}

Each subject is called MainTopic and it has a lot of topics underneath, like: JavaScript has NodeJS, Data Structures, and Algorithms as topic and Express is a subtopic of Node and so on...

I have a NodeJS API serving JSON to get the entire list of documents already stored in the database as well as each specific part of it, MainTopics, Topics from a given MainTopic, etc. etc... here you are the JSON it returns:

[
    {
        "topics": [
            {
                "subtopics": [
                    {
                        "resources": [
                            {
                                "_id": "5b857b00c346783a24cbdbb5",
                                "subtopic_id": "5b857ad0c346783a24cbdbb4",
                                "title": "Udemy Course",
                                "link": "https://udemy.com/dictionaires-nodejs",
                                "concluded": false,
                                "__v": 0
                            }
                        ],
                        "_id": "5b857ad0c346783a24cbdbb4",
                        "title": "Dictionaries",
                        "percentage_concluded": 0,
                        "topic_id": "5b857a12c346783a24cbdbae",
                        "__v": 0
                    }
                ],
                "_id": "5b857a12c346783a24cbdbae",
                "maintopic_id": "5b8565b90c927b2c47df7d9d",
                "title": "Node.js",
                "percentage_concluded": 0,
                "__v": 0
            },
            {
                "subtopics": [
                    {
                        "resources": [],
                        "_id": "5b857ab8c346783a24cbdbb3",
                        "title": "Lists",
                        "percentage_concluded": 0,
                        "topic_id": "5b857a1ac346783a24cbdbaf",
                        "__v": 0
                    }
                ],
                "_id": "5b857a1ac346783a24cbdbaf",
                "maintopic_id": "5b8565b90c927b2c47df7d9d",
                "title": "Java",
                "percentage_concluded": 0,
                "__v": 0
            },
            {
                "subtopics": [
                    {
                        "resources": [
                            {
                                "_id": "5b857a91c346783a24cbdbb2",
                                "subtopic_id": "5b857a6ec346783a24cbdbb1",
                                "title": "Udemy Course",
                                "link": "https://udemy.com",
                                "concluded": false,
                                "__v": 0
                            }
                        ],
                        "_id": "5b857a6ec346783a24cbdbb1",
                        "title": "Variables",
                        "percentage_concluded": 0,
                        "topic_id": "5b857a21c346783a24cbdbb0",
                        "__v": 0
                    }
                ],
                "_id": "5b857a21c346783a24cbdbb0",
                "maintopic_id": "5b8565b90c927b2c47df7d9d",
                "title": "Python",
                "percentage_concluded": 0,
                "__v": 0
            }
        ],
        "_id": "5b8565b90c927b2c47df7d9d",
        "title": "Programming Languages",
        "percentage_concluded": 30,
        "__v": 0
    }
]

I want to start the React part, but I am really not sure how to structure it, I mean, should I create 1 component to handle the whole amount of data requested or I should create a single component for each moving part? Like... a component for MainTopics, one for Topics, one for SubTopics and one for each Resource.

So far, I have the following Reac code:

App.js
components/
  Learning.js
  Resource.js
  Header.js

The main app file App.js

import React, { Component } from 'react';
import Header from './components/Header';

import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import Learning from './components/Learning';

import './index.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Header branding="Learn Tracker"/>
        <div className="container">
          <Learning />
        </div>
      </div>
    );
  }
}

export default App;

The other Learning.js :

import React, { Component } from 'react'
import Resource from './Resource';
import axios from 'axios';


class Learning extends Component {
    constructor(props){
        super(props);
        this.state = {
            resource: [{}]
        }
        this.fetchData();
    }

    fetchData(){
        axios.get('/api/all')
            .then(result => {
                this.setState({resource: result.data});
            })
            .catch(err => {
                console.log(err);
            });
    }

    render() {
        const {resource} = this.state;
        resource.map((resource) => {
            return (
                <Resource resource={resource} />
            )
        });
        return(
            <div>
                {resource}
            </div>
        );
    }
}

export default Learning;

The Resource.js :

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Resource extends Component {
  render() {
      const {resource} = this.props;
    return (
        <div className="card mb-3">
        <div className="card-header">
          <h4>{ resource[0].maintopic.title }</h4>
        </div>
        <div className="card-body">
            <h4 className="card-title">{ resource[0].maintopic.topic.title }</h4>
          <ul className="list-group">
            <li className="list-group-item">
            { resource[0].maintopic.topic.subtopic.title }
              <div className="card-body">
                <ul className="list-group list-group-flush">
                  <li className="list-group-item">Title: { resource[0].maintopic.topic.subtopic.resources[0].title }</li>
                  <li className="list-group-item">Link: { resource[0].maintopic.topic.subtopic.resources[0].link }</li>
                  <li className="list-group-item">Concluded: { resource[0].maintopic.topic.subtopic.resources[0].concluded }</li>
                </ul>
              </div>
            </li>
          </ul>
        </div>
      </div>
    )
  }
}

Resource.propTypes = {
    resource: PropTypes.object.isRequired
}

export default Resource;

And finally the Header.js :

import React from 'react'
import PropTypes from 'prop-types';

import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.css';
import '../index.css';

const Header = props => {
    const { branding } = props;

    return (
      <nav className="navbar navbar-expand-sm navbar-dark bg-primary mb-3 py-3">
        <div className="container">
            <a href="/" className="navbar-brand">{branding}</a>
            <div>
                <ul className="navbar-nav mr-auto">
                    <li className="nav-item">
                        <a href="/" className="nav-link">Home</a>
                    </li>
                    <li className="nav-item text-white"><p className="nav-link"><span className="branco">|</span></p></li>
                    <li className="nav-item">
                        <a href="/" className="nav-link">About</a>
                    </li>
                </ul>
            </div>
        </div>
      </nav>
    )
}

Header.defaultProps = {
    branding: "Learning Tracker"
}

Header.PropTypes = {
    branding: PropTypes.string.isRequired
}
export default Header;

Please, help me to understand how I could come to the best solution for the structure of the application.

Thank you in advance.

Best regards.

I think the best and the easiest way to arrange your file structure in react is by use of stand-alone components . Under this approach, you structure your app in the smallest units (components) possible. These components will contain all they need to run anywhere. The main advantage of this approach is that it encourages a high level of code reusability.

If you were to pluck out a component and plug it in in a totally different app, it would run exactly the same way it used to run in the previous app. Below how you could structure your app;

 ├── src │ ├── components // Dumb components should go here -> they should be stand-alone components │ │ ├── App // App should should render all the main topics │ │ │ ├── index.js // Component logic and jsx │ │ │ ├── index.test.js // Component tests │ │ │ ├── index.css // Component styles │ │ ├── Header // All components should have their own index.js and index.test.js files │ │ │ ├── index.js // Component logic and jsx │ │ │ ├── index.test.js // Component tests │ │ │ ├── index.css // Component styles │ │ ├── MainTopic // MainTopic should be a component on its own because it's repeated. It's in an array. │ │ │ ├── index.js // Component logic and jsx │ │ │ ├── index.test.js // Component tests │ │ │ ├── index.css // Component styles │ │ ├── SubTopic // SubTopic should be a component on its own because it's repeated. It's in an array. │ │ │ ├── index.js // Component logic and jsx │ │ │ ├── index.test.js // Component tests │ │ │ ├── index.css // Component styles │ │ ├── Topic // Topic should be a component on its own because it's repeated. It's in an array. │ │ │ ├── index.js // Component logic and jsx │ │ │ ├── index.test.js // Component tests │ │ │ ├── index.css // Component styles │ ├── index.test.js // Tests for non-components files │ ├── index.js │ ├── routes.js // All routes should be registered here 

It all depends on the application size and on the additional technologies (eg Redux) you might want to add to your app (now) or might considering using (adding on) in the future. React doesn't have opinions on how you put files into folders.

With that being said, here are some examples you might consider:

Grouping by features or/ and routes
[ put your CSS, JS, and other files together inside folders grouped by feature or route. ]

  common/
  Avatar.js
  Avatar.css
  APIUtils.js
  APIUtils.test.js
feed/
  index.js
  Feed.js
  Feed.css
  FeedStory.js
  FeedStory.test.js
  FeedAPI.js
profile/
  index.js
  Profile.js
  ProfileHeader.js
  ProfileHeader.css
  ProfileAPI.js

Grouping by file types
[ group similar files together ]

api/
  APIUtils.js
  APIUtils.test.js
  ProfileAPI.js
  UserAPI.js
components/
  Avatar.js
  Avatar.css
  Feed.js
  Feed.css
  FeedStory.js
  FeedStory.test.js
  Profile.js
  ProfileHeader.js
  ProfileHeader.css

These are some basic examples of simple apps. But if your app starts to grow larger you would consider dividing your components into separate folders depending on what task they are doing, making containers for your components and putting them inside of a separate folder. If you're using something like scss complainer you would probably make a separate folder for the styles and divide compiled CSS files from the scss ones. Additionally, if you use something like Redux you would have your actions & reducers folders, and probably a separate store folder (where you would configure your react-redux store ). That folder structure would go something like this:

/src
   /components     // where you put and divide all your components
      /posts       // folder containing all files relevant to your eg post feature
      /likes       // likewise, a folder containing all files relevant to your likes feature
      /home
   Header.js      // some of your other files that are used everywhere 
   Footer.js
   App.js        // your main  App.js file, if you decide to put it inside of your 'components' folder 
   ...
  /containers     // where you would put your containers, get all the data and pass it down to components as props 
     /HomeContainer.js
     /PostContainer.js
     /LikesContainer.js                               
  /actions        // all of for your action creators and types
  /reducers       // all of for your reducers, including your root reducer
  /utils          // all your helper methods, eg for your auth flow
  /styles         // your css (or/ and scss) files
  /assets         // your logos, images, and other static files
  ...etc
  index.js        // Your main index.js file inside of the root 'src' folder

I also suggest reading this: Thinking in React .
It might give you slight hints on how to approach creating apps using React .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM