diff --git a/Programming_Languages/Frameworks/React/Hooks/Custom_hook_examples.md b/Programming_Languages/Frameworks/React/Hooks/Custom_hook_examples.md new file mode 100644 index 0000000..e62e2e1 --- /dev/null +++ b/Programming_Languages/Frameworks/React/Hooks/Custom_hook_examples.md @@ -0,0 +1,79 @@ +--- +categories: + - Programming Languages +tags: + - javascript + - react + - react-hooks +--- + +# Custom hook examples + +## Determine viewport width + +### Hook + +```js +// useViewportWidth.js +import { useEffect, useState } from "react"; + +export default function (viewportWidth) { + const [matchesViewportWidth, setMatchesViewportWidth] = useState(false); + + useEffect(() => { + const handleResize = () => + window.innerWidth < viewportWidth + ? setMatchesViewportWidth(true) + : setMatchesViewportWidth(false); + + window.addEventListener("resize", handleResize); + + // Call on initialization to determine initial width + handleResize(); + + // Clean-up listener to prevent memory leaks + return () => window.removeEventListener("resize", handleResize); + }, [viewportWidth]); + + return matchesViewportWidth; +} +``` + +### Unit test + +```js +import useViewportWidth from "./useViewportWidth"; +import { fireEvent } from "@testing-library/react"; +import { act } from "react-dom/test-utils"; +import { renderHook } from "@testing-library/react-hooks"; + +describe("useViewportWidth", () => { + it("returns `true` when window resized to mobile viewport width", () => { + // Arrange + const { result } = renderHook(() => useViewportWidth(768)); + + // Act + act(() => { + window.innerWidth = 500; + fireEvent(window, new Event("resize")); + }); + + // Assert + expect(result.current).toBe(true); + }); + + it("returns `false` when window resized to width greater than mobile viewport", () => { + // Arrange + const { result } = renderHook(() => useViewportWidth(768)); + + // Act + act(() => { + window.innerWidth = 1058; + fireEvent(window, new Event("resize")); + }); + + // Assert + expect(result.current).toBe(false); + }); +})``; +``` diff --git a/Programming_Languages/Node/Architecture/Process_object.md b/Programming_Languages/Node/Architecture/Process_object.md deleted file mode 100644 index 70eab18..0000000 --- a/Programming_Languages/Node/Architecture/Process_object.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -categories: - - Programming Languages -tags: - - backend - - node-js ---- - -# The `process` object in Node.js - -`process` is a global object accessible from anywhere in a Node application. It contains functionality that allows us to interact with information about the current process instance. - -For example, we can use it to get environment information, read environment variables, communicate with the terminal and exit the current process. - -## Managing runtime environments - -See [Managing Environments](/Programming_Languages/Node/Architecture/Managing_environments.md). - -## Accessing arguments: `process.argv` - -We can use `process.argv` to return an array containing the command-line arguments passed when a Node process was launched. This could be a whole-app entrypoint (i.e. `index.js`) or a single file we are running. - -For instance if we run the following file: - -```js -// process-demo.js -console.log(3 + 3); -console.log(process.argv); -``` - -We get: - -```bash -6 -[ - '/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node', - '/Users/thomasbishop/prepos/testNode.js' -] -``` - -The first value is a reference to the Node runtime binary. The second is the file that was passed to node. - -If we passed in a parameter we would get that too: - -``` -node process-demo.js --fakeFlag -``` - -Gives us: - -```bash -[ - "/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node", - "/Users/thomasbishop/prepos/testNode.js", - "--fake-flag", -] -``` - -When writing command line Node applications we could easily write functions that parse standard input. For example: - -```js -function parseStandardInput(flag) { - let indexAfterFlag = process.argv.indexOf(flag); - console.log(process.argv[indexAfterFlag]); -} -``` - -Say we ran a program that took in a username: - -```bash -node userName.js --user Thomas -``` - -Then `parseStandardInput("--user")` would give us `"thomas"` - -## Standard input and output `process.stdout` - -```js -// alpha.js -process.stdout.write("Hello from file \n"); -``` - -```bash -$ node alpha.js -$ Hello from file -``` diff --git a/Programming_Languages/Node/Miscellaneous/io_with_files.md b/Programming_Languages/Node/Miscellaneous/io_with_files.md deleted file mode 100644 index 3e229dc..0000000 --- a/Programming_Languages/Node/Miscellaneous/io_with_files.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -categories: - - Programming Languages -tags: - - backend - - node-js ---- - -# I/O with files - -## Read file from directory (JSON) - -```js -const fs = require('fs'); - -// Get raw JSON -let inputJson = fs.readFileSync('source.json'); - -// Convert to JS -let data = JSON.parse(inputJson); -``` - -## Write file to directory (JSON) - -```js -let newFile = 'new.json'; - -// Write JS object to JSON file as JSON -fs.writeFileSync(writePath, JSON.stringify(alienblood)); -``` - -## Delete file from directory - -```js -let filePath = 'file-to-delete.json'; -fs.unlinkSync(filePath); -``` - -## Applications - -### Overwrite file - -```js -if (fs.existsSync(writePath)) { - fs.unlinkSync(writePath); - fs.writeFileSync(writePath, JSON.stringify(someJS)); -} else { - fs.writeFileSync(writePath, JSON.stringif(someJS)); -} -``` diff --git a/Programming_Languages/Node/Modules/Core/fs.md b/Programming_Languages/Node/Modules/Core/fs.md index 879a141..7437063 100644 --- a/Programming_Languages/Node/Modules/Core/fs.md +++ b/Programming_Languages/Node/Modules/Core/fs.md @@ -15,14 +15,14 @@ Every method associated with `fs` has a _blocking_ and _asynchronous_ implementa The synchronous methods are useful to have in some contexts but in general and with real-world applications, you should be using the async implementation so as to accord with the single-threaded event-driven architecture of Node. -## Methods +## Common I/0 methods ### Read directory Return a string array of all files in the current directory. ```js -fs.readdir('./', function (err, files) { +fs.readdir("./", function (err, files) { if (err) { console.error(err); } else { @@ -30,3 +30,75 @@ fs.readdir('./', function (err, files) { } }); ``` + +### Read from file + +```js +fs.readFile("./lorem.md", "UTF-8", function (err, fileContents) { + console.log(fileContents); +}); +``` + +### Write to file + +```js +let md = `A new file`; + +fs.writeFile("testFile.md", md.trim(), function () { + console.log("File was created"); +}); +``` + +### Appending to file + +```js +fs.appendFile("testFile.md", "new content"); +``` + +### Create directory + +```js +if (!fs.existsSync("directory_name")) { + fs.mkdir("directory_name", function (err) { + if (err) { + console.err(err); + } + }); +} else { + console.warn("Directory already exists"); +} +``` + +### Rename and remove files + +```js +fs.rename("./filename.js", "./newname.js", function () { + console.log("file renamed"); +}); +``` + +```js +// Remove file +fs.unlink("./file-to-delete", function (err) { + if (err) { + console.error(err); + } +}); +``` + +### Rename and remove directories + +```js +// Best to use synchronous method here +fs.rmSync("/dir", { recursive: true, force: true }); +``` + +## Streams + +See [Handling streams with fs](/Programming_Languages/Node/Streams.md) + +In the examples above of reading from a file, the `fs.readFile()` method waits until the entire file has been read before executing the callback. It's obvious why this might not be ideal in certain cases. If the file is very large you are utilising a lot of memory for a single process. Additionally, the data you need might appear early in the file, in which case, once you find the data you want, there is no need to read to the end of the file. + +This is why the ability to read files and data as streams exists in Node.js. Streams increase memory and time efficiency. As you are not necessarily reading the whole file, + +Streams are more memory efficient since you are not waiting for the whole file to be read before acting. This also means you can start execution quicker. diff --git a/Programming_Languages/Node/Modules/Core/process.md b/Programming_Languages/Node/Modules/Core/process.md new file mode 100644 index 0000000..06ba485 --- /dev/null +++ b/Programming_Languages/Node/Modules/Core/process.md @@ -0,0 +1,145 @@ +--- +categories: + - Programming Languages +tags: + - backend + - node-js +--- + +# The `process` module in Node.js + +`process` is a core module and a global object accessible from anywhere in a Node.js application. It contains functionality that allows us to interact with information about the current process instance. + +For example, we can use it to get environment information, read environment variables, communicate with the terminal and exit the current process. + +## Managing runtime environments + +See [Managing Environments](/Programming_Languages/Node/Architecture/Managing_environments.md). + +## Accessing arguments: `process.argv` + +We can use `process.argv` to return an array containing the command-line arguments passed when a Node process was launched. This could be a whole-app entrypoint (i.e. `index.js`) or a single file we are running. + +For instance if we run the following file: + +```js +// process-demo.js +console.log(3 + 3); +console.log(process.argv); +``` + +We get: + +```bash +6 +[ + '/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node', + '/Users/thomasbishop/prepos/testNode.js' +] +``` + +The first value is a reference to the Node runtime binary. The second is the file that was passed to node. + +If we passed in a parameter we would get that too: + +``` +node process-demo.js --fakeFlag +``` + +Gives us: + +```bash +[ + "/Users/thomasbishop/.nvm/versions/node/v16.10.0/bin/node", + "/Users/thomasbishop/prepos/testNode.js", + "--fake-flag", +] +``` + +When writing command line Node applications we could easily write functions that parse standard input. For example: + +```js +function parseStandardInput(flag) { + let indexAfterFlag = process.argv.indexOf(flag); + console.log(process.argv[indexAfterFlag]); +} +``` + +Say we ran a program that took in a username: + +```bash +node userName.js --user Thomas +``` + +Then `parseStandardInput("--user")` would give us `"thomas"` + +## Standard input and output + +Below is the most basic use case: writing to the output. + +```js +// alpha.js +process.stdout.write("Hello from file \n"); +``` + +``` +node alpha.js +Hello from file +``` + +Typically we want to write and read data that the user provides. To do this we need to wait on that event. So we use Node's asynchonous [event listeners](/Programming_Languages/Node/Modules/Core/Node_JS_events_module.md). We wait on the `data` event: + +```js +process.stdin.on("data", (data) => { + process.stdout.write(data.toString().trim()); +}); + +process.stdout.write("\n What is your name? \n"); +process.stdout.write(` \n > `); +``` + +This waits for whatever input is given and then echoes it. + +Currently there is no way to end this process; it will just keep echoing the input. + +So we add an exit clause: + +```js +process.stdin.on("data", (data) => { + process.stdout.write(data.toString().trim()); + process.exit(); +}); +``` + +We can also execute functionality on the exit event: + +```js +process.on("exit", () => { + // Do something +}); +``` + +> Timings can also obviously be managed via the `setTimeout` and `setInterval` methods. + +### Additional useful methods + +```js +process.stdout.clearLine(); +process.stdout.cursorTo([int]); +``` + +### `readline` + +The core `readline` module simplifies the handling of standard input and output by providing a wrapper. It reads the input stream line by line. Basic usage: + +```js +var readline = require("readline"); + +var rl = readline.createInterface(process.stdin, process.stdout); + +rl.question("What is your age? ", (age) => { + console.log("Your age is: " + age); +}); +``` + +Usage scenarios at: https://www.geeksforgeeks.org/node-js-readline-module/ diff --git a/Programming_Languages/Node/Modules/Core/v8.md b/Programming_Languages/Node/Modules/Core/v8.md new file mode 100644 index 0000000..0a8f4ba --- /dev/null +++ b/Programming_Languages/Node/Modules/Core/v8.md @@ -0,0 +1,13 @@ +--- +categories: + - Programming Languages +tags: + - backend + - node-js +--- + +# v8 + +The v8 module is useful for providing information about the resource-usage of your Node.js apps, such as memory usage and capacity. + +// TODO: Add example usage diff --git a/Programming_Languages/Node/Streams.md b/Programming_Languages/Node/Streams.md new file mode 100644 index 0000000..948624f --- /dev/null +++ b/Programming_Languages/Node/Streams.md @@ -0,0 +1,75 @@ +--- +categories: + - Programming Languages +tags: + - backend + - node-js + - streams +--- + +# Handling streams with `fs` + +When reading from a file, the [`fs.readFile()`](/Programming_Languages/Node/Modules/Core/fs.md) method waits until the entire file has been read before executing the callback. It's obvious why this might not be ideal in certain cases. If the file is very large you are utilising a lot of [memory](/Computer_Architecture/Memory/Memory.md) for a single process. Additionally, the data you need might appear early in the file, in which case, once you find the data you want, there is no need to read to the end of the file. An example of this in practice is watching a Netflix film: we don't have to wait for the whole film to download, we can start watching it immediately because it is passed to us in chunks. + +## Reading streams + +This is why the ability to read files and data as streams exists in Node.js. Streams boost memory and time efficiency. As you are not necessarily reading the whole file, you can extract the data you need quickly and you are not putting the whole file in memory. + +When read as a stream, the file is broken up into smaller chunks. Readable streams raise data events and pass the chunks to our callbacks. Hence we don't have to wait for the whole file before registering data chunks. + +## Implementation + +Instead of, e.g : + +```js +fs.readFile("./lorem.md", "UTF-8", function (err, fileContents) { + console.log(fileContents); +}); +``` + +We would rewrite to: + +```js +let stream = fs.createReadStream("./lorem.md", "UTF-8"); + +let data; + +stream.once("data", (chunk) => { + console.log("read stream started"); +}); + +stream.on("data", (chunk) => { + data += chunk; + console.log(data); +}); + +stream.on("end", () => console.log("stream ends")); +``` + +This time we don't include a callback since we are not waiting on the whole file. Instead we handle the file as a stream. + +We use `once` to do something at the moment the stream starts to be read. + +We use `on` to target the `"data"` and `"end"` events. We use this to log the chunks via the `data` variable. + +## Writing streams + +With write stream, we break data up and pass this to a reader as a stream. It is what creates a stream in the first place. + +For example we could create a stream that handles `stdin` and writes this to a file in chunks: + +```js +var stream = fs.createWriteStream("lorem.txt") + +process.stdin.once("data", (data) => { + stream.write(data, function() => { + // data is now written. + }) +}) + +process.on("exit", function () { + stream.close() +}) +``` + +Note that we always have to close the stream on exit diff --git a/_scripts/auto_save.sh b/_scripts/auto_save.sh index 6b693b8..5820617 100755 --- a/_scripts/auto_save.sh +++ b/_scripts/auto_save.sh @@ -4,9 +4,9 @@ # It is aliased to `cs-update` in .zshrc -NOTES_PATH="/home/thomas/repos/computer_science" -SPACE_TO_UNDERSCORE="/home/thomas/repos/computer_science/_scripts/space_to_underscore_filename.sh" -CLEAN_IMAGE_DIRECTORY="/home/thomas/repos/computer_science/_scripts/clean_image_directory.sh" +NOTES_PATH="/Users/thomasbishop/prepos/computer_science" +# SPACE_TO_UNDERSCORE="/home/thomas/repos/computer_science/_scripts/space_to_underscore_filename.sh" +# CLEAN_IMAGE_DIRECTORY="/home/thomas/repos/computer_science/_scripts/clean_image_directory.sh" cd "$NOTES_PATH" diff --git a/node-scratch.js b/node-scratch.js new file mode 100644 index 0000000..f58382f --- /dev/null +++ b/node-scratch.js @@ -0,0 +1,7 @@ +process.stdin.on("data", (data) => { + process.stdout.write(data.toString().trim()); + process.exit(); +}); + +process.stdout.write("\n What is your name? \n"); +process.stdout.write(` \n > `);