Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bring a </div> closer to its <div> using React/Angular/Vue?

Prelude

Seasoned C (say) developers will squirm at the sight of a 200-line function. They will strive to divide it into (say) ten functions of 20 lines each. Loosely speaking, the objective is for a function to never cross one screen.

Context (update)

If a desktop (C, say) application is written modularly, it's possible to locate a bug easily. Look in all functions called by main. Identify the culprit; look inside; recurse. By comparison HTML development is a nightmare. When a flaw is discovered or an improvement is needed, it's very hard to narrow the scope of what should be modified. Is there a better tool for modularity than server-side templates or a client-side library? Are React/Angular/Vue suitable for the job? How?

Motivation

Web developers face the same issue. It is desirable for the lines between an opening <div> and its corresponding closing </div> to never cross one screen. If the two cannot be simultaneously seen in one screen, it is much harder to keep a good mental image of the code.

A templating engine, say Jinja, can be used to split an HTML file.

For example, with a file

<div class="main">
    <div class="left">
        <!-- many lines -->
    </div>
    <div class="right">
        <!-- many lines -->
    </div>
</div>

Jinja's derivation can be used to split the HTML file to a parent and child files.

<div class="main">
    {% block left %}
    {% endblock %}
    {% block right %}
    {% endblock %}
</div>

{% extends "main.html" %}
{% block left %}
    <!-- many lines -->
{% endblock %}
{% block right %}
    <!-- many lines -->
{% endblock %}

This is satisfying in a way reminiscent of splitting functions in, say, the C language. There the hallmark of ugliness in a long function is that indentation also becomes excessive, and then it also becomes difficult to see exactly where a loop begins and ends.

The D3.js can likewise be used. The HTML file above becomes a pair of HTML and JS files.

<div class="main">
</div>

let main = d3.select("main")
let left = main.append("div")
               .attr("class", "left");
let right = main.append("div")
                .attr("class", "right");

(Or, for industrial-strength use of D3 for this objective, see here.)

Question

Neither of these solutions feels right. They feel like using a powerful tool to do something quite simple, and a newcomer to the code (or oneself after an absence) does not see with lucidity something that is otherwise nearly trivial.

How can the first HTML file above be split using React/Angular/Vue to make sure that <div class="main"> and its closing </div> remain only a few lines apart no matter how much code goes into the left and right DIVs?

like image 443
Calaf Avatar asked Nov 21 '19 13:11

Calaf


People also ask

How to center a Div in react?

To center a div in React, set its display property to flex and its alignItems and justifyContent properties to center. The div’s content will be horizontally and vertically centered. Extract the style into a variable. you can center a div by writing your CSS in a file with an .css extension and importing it.

How to display all the elements inside the parent Div in HTML?

Approach 1: In this approach, we have set the display: flex and flex-direction: row to the parent div of all the div elements. Due to the flex-direction: row property all the elements inside the parent div will be shown in a single row. Users can see that all div elements inside the parent div are displaying inline.

How to display all div elements side by side in HTML?

The display:inline-block property will set the all div elements side by side. Users can see all div elements displaying inline. Approach 3: In this approach, we will apply the float: left property to all the div elements to display them inline.

How to hide and show a Div in JavaScript?

To hide a div , first we need to access the div element inside the JavaScript using the document.getElementById () method then set its style.display property to none. To show an div back, we need to update the style.display property to block. We also can hide a div by setting it’s element style.visibility property to hidden.


2 Answers

You have a really thoughtful question. I feel that my answer is a bit simple, so perhaps I misunderstood the goal of your question.

React and Vue leverage components to organize templates and abstract away the complexity of the DOM. You can encapsulate as much behavior as you'd like inside of these components.

From a Vue POV (though react has similar tools to accomplish the same goals)... if you're going for fewer lines of code, you could encapsulate the entirety of the "left" and "right" (their behavior, styles, and templates) as components*. If the two components do not share any state or data, this becomes very simple and clear as you do not need to pass any props down.


Code example (in Vue)

This is an overly simple example and usually MyPage.vue would have additional behavior, such as loading, animations, or setting up the initial app's data.

// MyPage.vue
<template>
    <div>
         <v-left/>
         <v-right/>
    </div>
</template>

<script>
import VRight from '@/components/right.vue';
import VLeft from '@/components/left.vue';

export default {
    components: {
        VRight,
        VLeft
    }
}
</script>

Finally, this might be a bit too covered in Vue terminology, but for some great illustrations of code organization (for any language or framework) are in this document.

The measure of code complexity is not only in lines of code in a given function but also in the number of places you need to touch when implementing something or the risk of breaking other areas of the code.

One of the most brittle areas of frontend code is CSS, this is why packaging CSS with components (either using a CSS-in-JS approach or using Vue's scoped styles) makes a huge improvement in the stability and reusability of the code you write.

I hope this was helpful!!

* (there are reasons why doing this isn't the best choice in a lot of cases)

like image 199
Jess Avatar answered Sep 30 '22 15:09

Jess


If I understand correctly your question, I think you can obtain what you are after also using Svelte, which has similar goals to React/Vue but for some aspects is more a component compiler than a framework.

The official tutorial is very quick to read/play with and teaches almost everything there is to know.

In your case you can look at this playground:

App.svelte - main application file

<script>
    import Main from './Main.svelte';
    import Left from './Left.svelte';
    import Right from './Right.svelte';
</script>

<Main>
    <Left />
    <Right />
</Main>

Main.svelte - <Main> component (<slot> represents the contents from the caller of the component - in this case it contains the "calls" to Left and Right)

<style>
...
</style>

<div class="main">
    <slot></slot>
</div>

Left.svelte - <Left> component

<script>
    import Box from './Box.svelte';
</script>

<Box title="Left">
    <p>
    ...
    </p>
</Box>

Right.svelte is essentially equal to Left.svelte

Box.svelte - common <Box> inner component used by both <Left> and <Right>

<script>
    export let title = "box";
</script>

<style>
    ...
</style>

<div class="box">
    <h3>
        {title}
    </h3>
    <slot></slot>
</div>

(here the parts common to Left and Right are factored into a Box component, but this is obviously not necessary)

For the sake of completeness, to turn the example into a complete program:

main.js

import App from './App.svelte';

const app = new App({
    target: document.body,
});

export default app;

package.json

{
  "name": "svelte-demo",
  "version": "1.0.0",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public"
  },
  "devDependencies": {
    "rollup": "^1.12.0",
    "rollup-plugin-commonjs": "^10.0.0",
    "rollup-plugin-livereload": "^1.0.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-svelte": "^5.0.3",
    "rollup-plugin-terser": "^5.1.2",
    "svelte": "^3.0.0"
  },
  "dependencies": {
    "sirv-cli": "^0.4.4"
  }
}

rollup.config.js:

import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';

const production = !process.env.ROLLUP_WATCH;

export default {
    input: 'src/main.js',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            // enable run-time checks when not in production
            dev: !production,
            // we'll extract any component CSS out into
            // a separate file — better for performance
            css: css => {
                css.write('public/build/bundle.css');
            }
        }),

        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration —
        // consult the documentation for details:
        // https://github.com/rollup/rollup-plugin-commonjs
        resolve({
            browser: true,
            dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
        }),
        commonjs(),

        // In dev mode, call `npm run start` once
        // the bundle has been generated
        !production && serve(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};

function serve() {
    let started = false;

    return {
        writeBundle() {
            if (!started) {
                started = true;

                require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
                    stdio: ['ignore', 'inherit', 'inherit'],
                    shell: true
                });
            }
        }
    };
}

and then:

npm install
npm run dev

(please note that this is very essentially what the official svelte templeate creates using npx degit sveltejs/template my-svelte-project, as decribed on the landing page)

The nice thing is that Svelte compiles to standard JavaScript classes, so it's possible to use its components from regulard JavaScript. It's a no-framework framework from this point of view. See for example this article

like image 21
Marco Pantaleoni Avatar answered Sep 30 '22 15:09

Marco Pantaleoni