Categories
discuss

ReactJS double render for a Boolean state with useState

I’m just playing around with ReactJS and trying to figure out some strange behavior with the useState hook.

A component should not re-rendered if the state is set with the same primitive value (Boolean) as it was before

const useScroll = ({positionToCross = 10}) => {

    const window = useWindow();
    const [isPositionCrossed, setIsPositionCrossed] = useState(window.scrollY > positionToCross);

    useEffect(() => {

        const onScroll = function (e) {

            window.requestAnimationFrame(function () {
                const lastKnownScrollPosition = window.scrollY;
                setIsPositionCrossed(lastKnownScrollPosition > positionToCross);
            });

        }

        window.addEventListener('scroll', onScroll);

        return () => {
            window.removeEventListener("scroll", onScroll)
        }

    }, []);


    console.log(`useScroll - render window.scrollY = ${window.scrollY.toFixed(0)} isPositionCrossed = `, isPositionCrossed)
    return {isPositionCrossed}
}

here is the console output – you can see the component and the hook are both rendered two times with “true” (after scrolled over 100px)

"useScroll - render window.scrollY = 101 isPositionCrossed = ", true
"useScroll - render window.scrollY = 103 isPositionCrossed = ", true

Answer

If you try simple code that on click handler setState and if you click two times and in each update state with same value the component again re-render. As react doc says:

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree. If you’re doing expensive calculations while rendering, you can optimize them with useMemo.

I hope the answers from this post and this github discussion help you to understand why this happens

and there are another related topics like this post and this one

Categories
discuss

Why is my Rust program running more that twice as slow as the Java equivalent?

I have a program that finds, for all integers less than or equal to the input, numbers that can be represented as the sum of two cubes, twice, aka the Ramanujan’s number problem.

I have written this in Java and Rust, however, it runs more than twice as slow in Rust as compared to Java.

Is there anything I can do to make it perform better, or otherwise improve it?

Rust code:

use num_integer::Roots;
fn main() {
    let v = 984067;
    // let v = 87539319;
    for i in 1..=v {
        ramanujan(i)
    }
}
fn ramanujan(m: i32) {
    let maxcube = m.cbrt();
    let mut res1 = 0;
    let mut res2 = 0;
    let mut _res3 = 0;
    let mut _res4 = 0;
    for i in 1..=maxcube {
        for j in 1..=maxcube {
            if i * i * i + j * j * j == m {
                res1 = i;
                res2 = j;
                break;
            }
        }
    }
    for k in 1..=maxcube {
        for l in 1..=maxcube {
            if k == res1 || k == res2 || l == res1 || l == res2 {
                continue;
            }
            if k * k * k + l * l * l == m {
                _res3 = k;
                _res4 = l;
                break;
            }
        }
    }
    // if ((res1 * res1 * res1) + (res2 * res2 * res2) == m) && ((res3 * res3 * res3) + (res4 * res4 * res4) == m) {
    //     println!("{} is representable as the sums of two different sets of two cubes!nThese values are {}, {}, and {}, {}.", m, res1, res2, res3, res4);
    // }
}

Java code:

public class Ramun {
    public static void main(String[] args) {
        int v = 984067;
        // int v = 87539319;
        for (int i = 1; i <= v; i++) {
            ramanujan(i);
        }
    }

    public static void ramanujan(int m) {
        int maxcube = (int) Math.round(Math.cbrt(m));
        int res1 = 0, res2 = 0, res3 = 0, res4 = 0;
        for (int i = 1; i <= maxcube; i++) {
            for (int j = 1; j <= maxcube; j++) {
                if (((i * i * i) + (j * j * j)) == m) {
                    res1 = i;
                    res2 = j;
                    break;
                }
            }
        }
        for (int k = 1; k <= maxcube; k++) {
            for (int l = 1; l <= maxcube; l++) {
                if (k == res1 || k == res2 || l == res1 || l == res2)
                    continue;
                if (((k * k * k) + (l * l * l)) == m) {
                    res3 = k;
                    res4 = l;
                    break;
                }
            }
        }
        // if (((res1 * res1 * res1) + (res2 * res2 * res2) == m) && ((res3 * res3 * res3) + (res4 * res4 * res4) == m)) {
        //     System.out.printf("%d is representable as the sums of two different sets of two cubes!%nThese values are %d, %d, and %d, %d.%n", m, res1, res2, res3, res4);
        // }
    }
}

Time output for both programs

Answer

The problem lies in RangeInclusive which can be expensive.

Here’s a version avoiding it:

fn ramanujan(m: i32) {
    let maxcube = m.cbrt() + 1; // we know it can't overflow
    let mut res1 = 0;
    let mut res2 = 0;
    let mut res3 = 0;
    let mut res4 = 0;

    for i in 1..maxcube {
        for j in 1..maxcube {
            if i * i * i + j * j * j == m {
                res1 = i;
                res2 = j;
                break;
            }
        }
    }

    for k in 1..maxcube {
        for l in 1..maxcube {
            if k == res1 || k == res2 || l == res1 || l == res2 {
                continue;
            }
            if k * k * k + l * l * l == m {
                res3 = k;
                res4 = l;
                break;
            }
        }
    }
}

Result:

From: 0.01s user 0.00s system 0% cpu 17.993 total
To: 0.00s user 0.01s system 0% cpu 3.494 total

I added a comment to #45222 to draw attention to this issue.


Looks like for_each() allows better performance too (as for loops are more natural and should have the same performance, it should be considered as a bug):

fn ramanujan(m: i32) {
    let maxcube = m.cbrt();
    let mut res1 = 0;
    let mut res2 = 0;
    let mut res3 = 0;
    let mut res4 = 0;

    (1..=maxcube).for_each(|i| {
        (1..=maxcube).try_for_each(|j| {
            if i * i * i + j * j * j == m {
                res1 = i;
                res2 = j;
                ControlFlow::Break(())
            } else {
                ControlFlow::Continue(())
            }
        });
    });
    (1..=maxcube).for_each(|k| {
        (1..=maxcube).try_for_each(|l| {
            if k != res1 && k != res2 && l != res1 && l != res2 && k * k * k + l * l * l == m {
                res3 = k;
                res4 = l;
                ControlFlow::Break(())
            } else {
                ControlFlow::Continue(())
            }
        });
    });
}
0.00s user 0.01s system 0% cpu 4.029 total
Categories
discuss

Setting values in thymeleaf using a map

I Generates a checkbox list from the map. Now how to set the value for the key (false / true) and now I can download it in UserConfig so that I can use this value in the rest of the project.

My view:

<body>
<main>
    <form th:action="@{/file/uploadFile}" enctype="multipart/form-data" method="POST"/>
    <fieldset>
        <legend>Generate Report</legend>
            <label> Upload File
                <input name="file" type="file" required/>
                <input type="submit" value="Upload"/>
            </label>
            <label th:each="item : ${userConfig.isEnableMap}">
                <input type="checkbox" id="" th:text="${item.key}" th:value="${item.value}"/>
            </label>
        </form>
    </fieldset>
</main>
</body>

My class UserConfig :

    @Component
public class UserConfig {

    private Map<String, Boolean> isEnableMap = new HashMap<>();

    public UserConfig() {
        isEnableMap.put(EnableProcess.MONTHLY_TIME_UPDATE.getName(), false);
        isEnableMap.put(EnableProcess.SUM.getName(), false);
        isEnableMap.put(EnableProcess.HIDE_COLUMNS.getName(), true);
    }

    public UserConfig(Map<String, Boolean> isEnableMap) {
        this.isEnableMap = isEnableMap;
    }

    public Map<String, Boolean> getIsEnableMap() {
        return isEnableMap;
    }

    public void setIsEnableMap(Map<String, Boolean> isEnableMap) {
        this.isEnableMap = isEnableMap;
    }


    public enum EnableProcess {
        MONTHLY_TIME_UPDATE("Monthly time update"), SUM("Sum"), HIDE_COLUMNS("Hide columns");

        private final String name;

        EnableProcess(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

Controller

  @PostMapping(value = "/uploadFile", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> uploadFile(@RequestParam("file") MultipartFile file, @ModelAttribute("userConfig") UserConfig userConfig) {
    String fileName = file.getOriginalFilename();
    if (getExtension(fileName).equals("XLSX") || getExtension(fileName).equals("XLS")) {
        XSSFWorkbook workbook = reportService.processFile(file);
        reportService.writeWorkbook(workbook);
    }
    Resource resource = new ClassPathResource("temp/" + reportConst.getTempFileName());
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + reportConst.getTempFileName() + """);
    return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

I do not use the database. It only needs the values to be saved for the purpose of generating the report

Answer

With Preprocessing (if I got you right), we could try something like:

<input th:field="*{userConfig.isEnableMap['__${item.key}__']}" ... />

… assuming the rest works. 😉

Categories
discuss

How can I specify location of AndroidManifest.xml?

I’m porting a module from Eclipse to Android Studio/Gradle, and need to specify the locations of my sources, resources, and manifest:

sourceSets {
    main {
        manifest {
            srcFile './AndroidManifest.xml'
        }
        java {
            srcDirs = ["src"]
        }
        resources {
            srcDirs = ["resource"]
        }
    }
}       

Android Studio/Gradle seems perfectly happy with my java and resources entries, but balks at my manifest entry:

No signature of method: build_b4wnchd9ct4a5qt388vbbtbpz.sourceSets() is applicable for argument types: (build_b4wnchd9ct4a5qt388vbbtbpz$_run_closure2) values: [build_b4wnchd9ct4a5qt388vbbtbpz$_run_closure2@35290d54]

All of my googling and searching SO suggests that this should have worked.

Arctic Fox, 2020.3.1. Not sure which version of Gradle came with it.

Answer

Ahh, figured it out. Leaving here in case someone else has the same question.

Add an android.sourceSets.manifest.srcFile entry to your module’s build.gradle file:

android {
    ...
    sourceSets {
        main {
            manifest {
                srcFile './AndroidManifest.xml'
            }
        }
    }
}

or simply:

android {
    ...
    sourceSets.main.manifest.srcFile './AndroidManifest.xml'
}

My biggest mistake was not putting the sourceSets directive inside the android directive.

Categories
discuss

How to setup lint-staged for Vue projects?

I created a new Vue3 app using the Vue CLI and selected Prettier for my linter config. I want to use commitlint, husky and lint-staged to validate commit messages and lint the code before pushing it.

What I did

Based on https://commitlint.js.org/#/guides-local-setup I setup commitlint with husky

npm install --save-dev @commitlint/{cli,config-conventional}
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

npm install husky --save-dev
npx husky install
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'

Based on https://github.com/okonet/lint-staged#installation-and-setup I setup lint-staged

npx mrm@2 lint-staged

and inside the package.json I replace

"lint-staged": {
  "*.js": "eslint --cache --fix"
}

with

"lint-staged": {
  "*": "npm run lint"
}

The problem

When modifying the README.md file in the project to

# my-repo

---

new commit

and try to commit that I get the following error message

> git -c user.useConfigOnly=true commit --quiet --allow-empty-message --file -
[STARTED] Preparing...
[SUCCESS] Preparing...
[STARTED] Running tasks...
[STARTED] Running tasks for *
[STARTED] npm run lint
[FAILED] npm run lint [FAILED]
[SUCCESS] Running tasks...
[STARTED] Applying modifications...
[SKIPPED] Skipped because of errors from tasks.
[STARTED] Reverting to original state because of errors...
[SUCCESS] Reverting to original state because of errors...
[STARTED] Cleaning up...
[SUCCESS] Cleaning up...

✖ npm run lint:

> my-repo@0.1.0 lint
> vue-cli-service lint "/home/.../my-repo/README.md"

error: Parsing error: Invalid character at README.md:1:1:
> 1 | # my-repo
    | ^
  2 |
  3 | ---
  4 |


1 error found.
npm ERR! code 1
npm ERR! path /home/my-repo
npm ERR! command failed
npm ERR! command sh -c lint-staged

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/.../.npm/_logs/2021-12-27T10_07_27_498Z-debug.log
husky - pre-commit hook exited with code 1 (error)

What it should do

Only fix the files that have been modified. The linter knows about files it is able to fix (js, ts, vue, html, …).

When having a modified markdown file I get no errors when opening the terminal and run npm run lint. But I do get errors when using lint-staged with this setup "*": "npm run lint"

What is the correct setup for lint-staged to lint “lintable” files only?

Answer

Update regarding the comments

Other lint-staged syntaxes

I’ve suggested "**/*.{js,vue}": ["npm run lint:js:fix"], first of, lint:js:fix is subjective and up to you. This is what Kent C Dodds is using, so I’m just naming it in the same way.

But you could totally have lint:watermelon-potato-hehe instead, doesn’t matter.

Now, about your propositions:

  1. "**/*.{vue,js,jsx,ts,tsx}": "npm run lint", this one is targeting more extensions, which is totally fine. You may not really use .tsx/.jsx since it’s not really popular among Vue devs.
    About .ts itself, it may probably work good enough (maybe you’ll need to add some plugins to your ESlint configuration). I’m not into TS so I can’t really help on this one but it’s out of the husky/lint-staged scope anyway.
    Last time I started a Vue3 project, I’ve used Vitesse which has some nice defaults with TS, this may be a good start for you maybe.

As for the second part, since I like to setup my own ESlint config, with some simple and well documented API, we’re using eslint --ext .js,.vue --fix. That way I’m sure of what is happening and how to troubleshoot it if needed.
vue-cli-service lint may be a good default package aimed towards Vue with some defaults, I’m not sure what’s inside it and even if it’s probably just an ESlint with some baked-in configuration, again we prefer to make our own Vue configuration with vanilla ESlint.

So yeah, if you need to go fast, use vue-cli-service lint for some quick linting, if you want to have a better flow in your project and want to fine grain your config, use vanilla ESlint, you’ll get less trouble overall IMO.

  1. "**/*.{vue,js,jsx,ts,tsx}": "eslint --ext .vue,.js,.jsx,.ts,.tsx --fix". On the right side, we globally have the same lint:js:fix scripts but with additional extensions.

So, you may ask why are we even writing the extensions on the left side for lint-staged and on the right side for lint:js:fix? I’d answer that those are not really needed on the right side (AFAIK), because lint-staged will only run the command to the left list of extensions.
Here, we wanted to be more explicit about the exact extensions we’re targeting and also, it enables you to run npm run lint:js:fix in your CLI at any given point without getting errors on files ESlint is not handling (.txt, .json, .md, .jpg etc…).
So it could maybe be removed (not sure), fastest way to be sure is to try!

  1. "**/*.{vue,js,jsx,ts,tsx}": "eslint --fix", this one may work fine as explained in the previous paragraph. Didn’t tried it myself thought.
What about the other extensions?

Regarding .html, you should not have a lot of those in your Vue project. You could use the W3C validator to check for any errors if you really need it.
If you’re speaking about your HTML in the template tags in your .vue files, those will be ESlint’ed properly. If you setup a Prettier on top of it, you will also get some nice auto-formatting which is really awesome to work with (once your team has agreed on a .prettierrc config).

Regarding .json files, those are not handled by ESlint. ESlint is only for JavaScript-ish files. If you want to lint/format your .json or even any other extensions at all, you can aim towards NPM, find a package that suits your team’s needs and add it to your chain like "**/*.json": ["npm run lint-my-json-please"] and you should be good!

At the end, husky + lint-staged are not doing anything special really. They are tools to automate what you could write yourself in a CLI, so if it’s working when done manually and you’re happy with the result, you can put it in your config but you need to first found what the proper package and it’s configuration.


In your package.json, you could have the following

"scripts": {
  "lint:js": "eslint . --ext .js,.vue",
  "lint:js:fix": "eslint --ext .js,.vue --fix",
},

In your .lintstagedrc

{
  "**/*.{js,vue}": ["npm run lint:js:fix"]
}

In .husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run lint-staged

In .husky/commit-msg

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit ""

You can setup ESlint to watch any errors in your files in VScode (a lint + formatter when your files are saved is also doable pretty easily).

That way, you can run npm run lint:js to check the issues by yourself.
Otherwise, let husky run lint-staged and apply the eslint --fix to all of your .js and .vue files.

Your commitlint.config.js config should be okay!


As a reminder here, lint:js will scan all of your JS and Vue files.
While, when you commit and husky is executed (by running the lint:js:fix script), ONLY the files that you have touched will be linted (that’s the whole point of lint-staged).

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..