React Query

+++ draft = true +++ Reference Global state Avoid prop drilling Access data accoss our application without copying flowchart A["PostsContext()"] B["posts state: [posts, setPosts]"] C["status state: [status, setStatus]"] D["PostsContext()"] E["refetch function hook"] A--create-->B C--refer-->B D--refer-->B Global components: Not remove dedup requests export function PostsContext({ children }) { // Every time call `PostsContext` function, we will create bellow objects const [posts, setPosts] = React.useState([]); const [error, setError] = React.useState(); const [status, setStatus] = React.useState("loading"); const refetch = async () => { try { setStatus("loading"); const posts = await axios.get("/api/posts").then((res) => res.data); setPosts(posts); setStatus("success"); } catch (err) { setstatus("error"); setError(err); } }; const contextValue = React.useMemo(() => ({ posts, status, error, refetch, })); return <context.Provider value={contextValue}>{children}</context.Provider>; } Consumer export default usePosts() { const {posts, status, error, refetch} = React.useContext(context); // Every component use `usePosts` then `refetch` will be called at mounting time // Not remove dedup requesting React.useEffect(() => { refetch() }, []); return { posts, status, error, refetch, } } Fix dedup requests export function PostsContext({ children }) { // Every time call `PostsContext` function, we will create bellow objects const [posts, setPosts] = React.useState([]); const [error, setError] = React.useState(); const [status, setStatus] = React.useState("loading"); // Add new ref object which cannot reset between re-rendering const activePromiseRef = React.useRef(false); // Stick `refetch` function with a new ref object // If any other requests that happen while the promise is still pending we will reuse the promise from the original request const refetch = () => { if (!activePromiseRef.current) { activePromiseRef.current = async () => { try { setStatus("loading"); const posts = await axios.get("/api/posts").then((res) => res.data); setPosts(posts); } catch (err) { setStatus("error"); setError(err); } finally { activePromiseRef.current = false; } }(); // Execute immediately } // If any other requests that happen while the promise is still pending we will reuse the promise from the original request (we don't fire extra one) return activePromiseRef.current; }; const contextValue = React.useMemo(() => ({ posts, status, error, refetch, })); return <context.Provider value={contextValue}>{children}</context.Provider>; }

Seperate a job into multiple async jobs

+++ +++ Seperate a job into multiple async jobs Sometime when I make a rquest to get info from an API which do some specified task per request. Then job will take longtime to run if I have muliple requests. for (let i = 0; i < count; i++) { const responsePerRequest = request("Some data of i", i); } Total time = Total(responsePerRequest) Because of each request i is independence, then I can split these request into a jobs then call async Make a job executes a list of request async function childJob(subSetOfRequests) { // We can do sequencely subset of requests by synchoronous // For example in the case we make request to API using `axios` then we can do by for (let i = 0; i < subSetOfRequests.length; i++) { const response = await axios.post( `URL for request ${i}`, body_for_post_only, { params_or_headers, } ); } } Split request into list of subset requests function chunkArray(requests, chunkSize) { const listOfSubsets = []; for (let i = 0; i < requests.length; i++) { listOfSubset.push(requests.slice(i, i + chunkSize)); } return listOfSubsets; } Execute in main job async function mainJob(requests) { const listOfSubsets = chunkArray(requests, 3); // Chunk size = 3 for example // For each subset of requests, we can make async child job to run. // Using map built-in of array to transform a subset into a child job const promises = listOfSubsets.map((subset) => childJob(subset)); // Await all of child jobs to complete by using Promise.all and await const results = await Promise.all(promises); }

Build Objects

+++ +++ new in function call graph A["var john = new Person()"] B["{} - 0x001 in memory"] C["function Person() (without returned value) FUNCTION CONSTRUCTOR"] D["function Person() (with returned value)"] E["var john (refer to returned value)"] A--new-->B B--incase OK, function without return value change pointer this = {} -->C C--update {}-0x001 and assign to variable -->A B--incase NOK, function with return value change pointer this = {} --> D D-->E style C fill:#4287f5 function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); We can add new features for objects after creation » PERFECT !!! If we add new features at function contructor, then every execute the function contructor, the new of instance features (functions are objects) will take memory space We can add one (single object) to share all objects at prototype function Person(firstName, lastName) { console.log(this); this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); // We can add new features for objects after creation >> PERFECT !!! Person.prototype.getFullName = function () { return this.firstName + " " + this.lastName; }; // console.log(john.getFullname === jane.getFullname); // True console.log(john.getFullName()); Builin Functions Extension We can extend features/functions by attact them to prototype. Such as Javascript Engine wrapup the primitve value by the Object. var aString = new String("Hello"); // Then we can use the toLocatedString() in String.prototype aString.toLocateString(); From above idea, we can attach new features for the current objects of library/frameworks String.prototype.isLengGreaterThan = function (limit) { return this.length > limit; }; console.log("HoHai".isLengGreaterThan(3)); // True Object.create() To create new object from existen object which can be refer as __proto__ property var person = { firstName = "Default", lastName = "Default", greet: function() { return "Hi " + this.firstName } } // Set __proto__ of the new object (john) is person object var john = Object.create(person); // Can overwrite other properties john.firstName = "John"; console.log(john) Polyfill: Add new features that the framework/Java Engine may lack. For example, there is some lacked features of Java Engine from old browsers version. Then we need to fullfill these features to adapt with new browsers versions. Example of polyfill for Object.create

Build Objects in Javascript

This is a sample post intended to test the followings: A different post author. Table of contents. Markdown content rendering. Math rendering. Emoji rendering. new in function call graph A["var john = new Person()"] B["{} - 0x001 in memory"] C["function Person() (without returned value) FUNCTION CONSTRUCTOR"] D["function Person() (with returned value)"] E["var john (refer to returned value)"] A--new-->B B--incase OK, function without return value change pointer this = {} -->C C--update {}-0x001 and assign to variable -->A B--incase NOK, function with return value change pointer this = {} --> D D-->E style C fill:#4287f5 function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); We can add new features for objects after creation » PERFECT !!! If we add new features at function contructor, then every execute the function contructor, the new of instance features (functions are objects) will take memory space We can add one (single object) to share all objects at prototype function Person(firstName, lastName) { console.log(this); this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); // We can add new features for objects after creation >> PERFECT !!! Person.prototype.getFullName = function () { return this.firstName + " " + this.lastName; }; // console.log(john.getFullname === jane.getFullname); // True console.log(john.getFullName()); Builin Functions Extension We can extend features/functions by attact them to prototype. Such as Javascript Engine wrapup the primitve value by the Object. var aString = new String("Hello"); // Then we can use the toLocatedString() in String.prototype aString.toLocateString(); From above idea, we can attach new features for the current objects of library/frameworks String.prototype.isLengGreaterThan = function (limit) { return this.length > limit; }; console.log("HoHai".isLengGreaterThan(3)); // True Object.create() To create new object from existen object which can be refer as __proto__ property var person = { firstName = "Default", lastName = "Default", greet: function() { return "Hi " + this.firstName } } // Set __proto__ of the new object (john) is person object var john = Object.create(person); // Can overwrite other properties john.firstName = "John"; console.log(john) Polyfill: Add new features that the framework/Java Engine may lack. For example, there is some lacked features of Java Engine from old browsers version. Then we need to fullfill these features to adapt with new browsers versions. Example of polyfill for Object.create

Build Objects in Javascript

This is a sample post intended to test the followings: A different post author. Table of contents. Markdown content rendering. Math rendering. Emoji rendering. new in function call graph A["var john = new Person()"] B["{} - 0x001 in memory"] C["function Person() (without returned value) FUNCTION CONSTRUCTOR"] D["function Person() (with returned value)"] E["var john (refer to returned value)"] A--new-->B B--incase OK, function without return value change pointer this = {} -->C C--update {}-0x001 and assign to variable -->A B--incase NOK, function with return value change pointer this = {} --> D D-->E style C fill:#4287f5 function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); We can add new features for objects after creation » PERFECT !!! If we add new features at function contructor, then every execute the function contructor, the new of instance features (functions are objects) will take memory space We can add one (single object) to share all objects at prototype function Person(firstName, lastName) { console.log(this); this.firstName = firstName; this.lastName = lastName; } var john = new Person("John", "Doe"); var jane = new Person("Jane", "Doe"); console.log(john); console.log(jane); // We can add new features for objects after creation >> PERFECT !!! Person.prototype.getFullName = function () { return this.firstName + " " + this.lastName; }; // console.log(john.getFullname === jane.getFullname); // True console.log(john.getFullName()); Builin Functions Extension We can extend features/functions by attact them to prototype. Such as Javascript Engine wrapup the primitve value by the Object. var aString = new String("Hello"); // Then we can use the toLocatedString() in String.prototype aString.toLocateString(); From above idea, we can attach new features for the current objects of library/frameworks String.prototype.isLengGreaterThan = function (limit) { return this.length > limit; }; console.log("HoHai".isLengGreaterThan(3)); // True Object.create() To create new object from existen object which can be refer as __proto__ property var person = { firstName = "Default", lastName = "Default", greet: function() { return "Hi " + this.firstName } } // Set __proto__ of the new object (john) is person object var john = Object.create(person); // Can overwrite other properties john.firstName = "John"; console.log(john) Polyfill: Add new features that the framework/Java Engine may lack. For example, there is some lacked features of Java Engine from old browsers version. Then we need to fullfill these features to adapt with new browsers versions. Example of polyfill for Object.create

Advance Javascript (Part 1)

+++ draft = false +++ Advance JS: Primitive Datatype Strings, Numbers, Booleans, undefined, null, Symbols There are object wrappers wrapping these types, then we can access the methods of these objects. Objects Everything (except primitive types) are object Object: a collection of values Functions are objects. The different things are the internal properties such as [[Code]], [[Call]] Functions are objects Function Declaration // Function Declaration function functionName() { // Code block to execute } Function Expression // Function Expression let x = function functionName(val) { // Code block to execute console.log(val); }; // Because the function is object, then we can attact the new property x.userName = "HoHai"; Function contructor // Function contructor let x = new Function("val", "console.log(val);"); 4 ways to invoke a function As a function As a method As a contructor (new) Indirectly using call() and apply() Understand this this refer the object that function current called (executed) NOT declared: may be binding object or global object Determine at EXECUTE TIME, NOT ‘DECLARE TIME’ var name = "global"; var obj1 = { name: "obj1", func1: function () { console.log(this.name); }, }; obj1.func1(); // The object will be binded this time (executed time), not above var obj2 = { name: "obj2", func2: obj1.func1, // Try to refer the func1 }; obj2.func2(); var func6 = function () { console.log("func6"); }; // func6 is object (function), then we can set other attributes func6.nameFunc = "func6"; func6.func7 = function () { console.log(this); console.log(this.nameFunc); }; func6.func7(); Understanding Prototypes Almost Every object is linkedto another object. That linked object is called the prototype Inherits and methods from it’s prototype ancestry (prototype chain) call(), apply() Function methods Why we need to invoke function by these way: because we want to determite value of this let func1 = function () { console.log("Something..."); }; func1.call(); // Something func1.apply(); // Something Using call function.call(obj, arg1, arg2 ): The first argument will be come of value of this. Onr or more arguments to be sent to the function may follow Using apply function.apply(obj, [arg1, arg2]): The first argument will be come of value of this. Onr or more arguments to be sent to the function may follow in single array var user1 = { firstName: "Ho", lastName: "Hai", fullName: function () { return this.firstName + " " + this.lastName; }, }; var user2 = { firstName: "John", lastName: "Henry", fullName: function () { return this.firstName + " " + this.lastName; }, }; var greeting = function (term) { // the term arg only console.log(term + " " + this.firstName); // `this` will be available later }; greeting.call(user1, "Greeting..."); greeting.apply(user1, ["Greeting2."]); // Can invoke (extract method from a object then make a call with other object ) console.log(user1.fullName.call(user2)); bind method bind will create new method attached in the binding object // new method `morningGreet` will be created which attached the `user1` object var morningGreet = greeting.bind(user1, "Morning", "!"); One or more arguments can be included var user1 = { firstName: "Ho", lastName: "Hai", fullName: function () { return this.firstName + " " + this.lastName; }, }; var user2 = { firstName: "John", lastName: "Henry", fullName: function () { return this.firstName + " " + this.lastName; }, }; var greeting = function (term, term2) { // the term arg only console.log(term + " " + this.firstName + " " + term2); // `this` will be available later }; /* this = user1 term = "Morning" term2 = undefined */ var morningGreet = greeting.bind(user1, "Morning"); /* term2 = "!" */ morningGreet("!"); // Morning Ho ! /* The object is refered then all of changes will be affected in the binding method */ user1.firstName = "Kevin"; morningGreet("!"); // Morning Kevin ! /* Try to overwrite the refered object by the argument put in `call` BUT, NOT WORK. The `this` still refer to the binding object */ morningGreet.call(user2, "!"); // Morning Ho ! Invoking Functions as Contructors (using new) Contructor is just a function that is invoked using new Contructor returns an object Contructors are used to create multiple similar objects // function with name uppercase the first letter, indicate function can be used with `new' var Greeting = function () {}; // Create 2 objects var greet1 = new Greeting(); var greet2 = new Greeting(); the method fullName should be put in prototype. If we put in the contructor function then we will have multiple methods (it should be shared) function Users(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.fullName = function () { return this.firstName + " " + this.lastName; }; } var user1 = new Users("Ho", "Hai"); var user2 = new Users("Kevin", "Ho"); console.log(user1.fullName()); console.log(user2.fullName()); // Not the same functions console.log(user1.fullName === user2.fullName); // False

Builder Functions

+++ +++ Function builders A function can contain a nested function. The nested function can access from parent’s variable scope A function can receive a parameterized function A function can be composed from other functions Nested function // _inner function is nested in highOrderFunc function highOrderFunc(type) { function _inner(thing) { // Thing parameter will be visiable at calling time, not definition time return thing + type; } return _inner; // Return the function object, NOT calling function _innner() } // Same result, but using arrow style const highOrderArrowFunc = (type) => (thing) => thing + type; console.log(highOrderArrowFunc(1)(2)); // Return 3 console.log(highOrderArrowFunc(1)(2)); // Return 3 Use case: We can improve reusage by common the logic const typeOfTest = (type) => (thing) => typeof thing === type; const isFunction = typeOfTest("function"); const isObject = typeOfTest("object"); function func1() {} console.log(isFunction(func1)); // True const obj = {}; console.log(isObject(obj)); // True Passing a function in parameter function forEach(obj, fn) { let i; let l; // Define l variable to hold length value, so there is only one time to access the length for (i = 0, l = obj.length; i < l; i++) { fn.call(null, obj[i], i, obj); } } const obj = [1, 2, 3]; const myFn = (item, i, obj) => { console.log(`Item: ${item}, index: ${i}. Container: ${obj}`); }; forEach(obj, myFn); // Item: 1, index: 0. Container: 1,2,3 // Item: 2, index: 1. Container: 1,2,3 // Item: 3, index: 2. Container: 1,2,3 Building function for creating object this refer to instance object at creation time (new keyword) protype is visible only in function. This object will package all of method/properties that the new object can access (by property chain) function Component(props, context, updater) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue; } Component.prototype.isReactComponent = {}; Component.prototype.setState = function (partialState, callback) { if ( typeof partialState !== "object" && typeof partialState !== "function" && partialState != null ) { throw new Error( "setState(...): takes an object of state variables to update or a " + "function which returns an object of state variables." ); } this.updater.enqueueSetState(this, partialState, callback, "setState"); };

React Hooks

+++ +++ What is React Hook A Function with Stateful capabilities such as states in object of class How we implement stateful of function In the code below, I will attempt to implement the stateful function. The code will not work initially, but then I will correct it. function useMyHookState(initialValue) { let _innerValue = initialValue; const _setInnerValue = (newValue) => { _innerValue = newValue; }; return [_innerValue, _setInnerValue]; // Like `useState` function } function FunctionComponent() { const [count, setCount] = useMyHookState(0); // Create new `increaseCountFunc` which use `setCount` func to increase `count` by 1 const increaseCountFunc = () => { console.log(`Current Count: ${count}`); // count always is 0 setCount(count + 1); }; return { clickMe: increaseCountFunc, }; } const test = FunctionComponent(); test.clickMe(); // Current Count: 0 test.clickMe(); // Current Count: 0 test.clickMe(); // Current Count: 0 The problem is that count always remains 0 because it points to the original value, while setCount increases _innerValue by 1. To obtain the latest count, we can replace it with a function that returns _innerValue. function useMyHookState(initialValue) { let _innerValue = initialValue; const _setInnerValue = (newValue) => { _innerValue = newValue; }; const _getInnerValue = () => _innerValue; // Instead of returning the pointer may become the old one, we can return the function which can be called to get the lastest _innerValue return [_getInnerValue, _setInnerValue]; } function FunctionComponent() { const [getCount, setCount] = useMyHookState(0); const increaseCountFunc = () => { const _currentValue = getCount(); console.log(`Current Count: ${_currentValue}`); setCount(_currentValue + 1); }; return { clickMe: increaseCountFunc, }; } const test = FunctionComponent(); test.clickMe(); // Current Count: 0 test.clickMe(); // Current Count: 1 test.clickMe(); // Current Count: 2 Reference: https://legacy.reactjs.org/docs/hooks-state.html https://tannerlinsley.com/posts/react-hooks-the-rebirth-of-state-management

Chakra UI Notes

+++ +++ Chakra Notes Grid templateColumns: divide into columns, using repeat(6, 1fr) mean that seperate 6 columns colSpan: range from 1..max-number-column <Grid templateColumns="repeat(6, 1fr)" bg="gray.100"> <GridItem as="aside" colSpan={{ base: 6, lg: 2, xl: 1 }} bg="brand.500" minHeight={{ lg: "100vh" }} p={{ base: "20px", lg: "30px" }} > <Slidebar /> </GridItem> <GridItem as="main" colSpan={{ base: 6, lg: 2, xl: 5 }} p="30px"> <Navbar /> <Outlet /> </GridItem> </Grid> Table import { TableContainer, Table, Thead, Tbody, Tfoot, Tr, Th, Td, } from "@chakra-ui/react"; function JiraListControl({ onTagChange, onTagDelete }) { const data = useContext(DataTagContext); return ( <TableContainer> <Table variant="simple"> <Thead> <Tr> <Th w="25%">Tag name</Th> <Th w="60%">Jira Query</Th> <Th>Jira Count</Th> <Th>Edit Control</Th> </Tr> </Thead> <Tbody> {data.map((tag) => ( <TagRow tag={tag} onTagChange={onTagChange} onTagDelete={onTagDelete} key={tag.id} /> ))} </Tbody> <Tfoot> <Tr> <Th w="25%"></Th> </Tr> </Tfoot> </Table> </TableContainer> ); } function TagRow({ tag, onTagChange, onTagDelete }) { const [isEditing, setIsEditing] = useState(false); const [tagName, setTagName] = useState(tag.tagName); const [tagQuery, setTagQuery] = useState(tag.tagQuery); function handleEditTag() { if (isEditing) { tag.tagName = tagName; tag.tagQuery = tagQuery; onTagChange(tag); } setIsEditing(!isEditing); } return ( <Tr> {isEditing && ( <Td> <Input type="text" value={tagName} onChange={(e) => setTagName(e.target.value)} /> </Td> )} {!isEditing && ( <Td> <Box bg="green" p={1} borderRadius="md" color="white" textAlign="center" > {tagName} </Box> </Td> )} {isEditing && ( <Td> <Input type="text" value={tagQuery} onChange={(e) => setTagQuery(e.target.value)} /> </Td> )} {!isEditing && <Td>{tagQuery}</Td>} {/* <Td>{tag.count}</Td> */} <Td> {tag.count == "..." && <Spinner color="green" />} {tag.count == "ERROR" && <Text color="tomato">{tag.count}</Text>} {tag.count != "ERROR" && tag.count != "..." && <Text>{tag.count}</Text>} </Td> <Td> <HStack spacing="4"> <IconButton size="sm" icon={!isEditing ? <EditIcon /> : <CheckIcon />} onClick={() => handleEditTag(tag)} /> <IconButton size="sm" icon={<DeleteIcon />} onClick={() => onTagDelete(tag.id)} /> </HStack> </Td> </Tr> ); } Box textAlign: align text item in the box maxW = max width of box, using when want to limit width of box <Box textAlign="right" maxW="sm"> <Text>{jiraRow.assignee}</Text> </Box> HStack Hozirontal stack spacing: distance of items in HStack <HStack spacing="10px"> </HStack> Conditional rendering {...some mixed} { !isEditing && ( <Td> <Box bg="green" p={1} borderRadius="md" color="white" textAlign="center"> {tagName} </Box> </Td> ); } { isEditing && ( <Td> <Input type="text" value={tagQuery} onChange={(e) => setTagQuery(e.target.value)} /> </Td> ); } { !isEditing && <Td>{tagQuery}</Td>; } Changing icon <IconButton size="sm" icon={!isEditing ? <EditIcon /> : <CheckIcon />} onClick={() => handleEditTag(tag)} /> Common properties: maxW: max width m, mt…: margin

React Custom Hooks

+++ +++ React Custom Hook Follow the link: https://blog.logrocket.com/developing-responsive-layouts-with-react-hooks/ Create the new custom hook to: Any event resize change will trigger rendering new components ( or ) The logic: resize event » setWind (thanks to useEffect hook and event listener) » width changed » re-evaluate width < breakpoint » new component render const useViewport = () => { // Declare a new state variable with the "useState" Hook const [width, setWidth] = React.useState(window.innerWidth); React.useEffect(() => { /* Inside of a "useEffect" hook add an event listener that updates the "width" state variable when the window size changes */ const handleWindowResize = () => setWidth(window.innerWidth); window.addEventListener("resize", handleWindowResize); return () => window.removeEventListener("resize", handleWindowResize); /* passing an empty array as the dependencies of the effect will cause this effect to only run when the component mounts, and not each time it updates. We only want the listener to be added once */ }, []); // Return the width so we can use it in our components return { width }; }; const MyComponent = () => { const { width } = useViewport(); const breakpoint = 620; return width < breakpoint ? <MobileComponent /> : <DesktopComponent />; }; Optimizing performance with a Context Wrap chidren with the viewportContext.Provider Rewrite useViewPort using value of viewportContext object const viewportContext = React.createContext({}); const ViewportProvider = ({ children }) => { // This is the exact same logic that we previously had in our hook const [width, setWidth] = React.useState(window.innerWidth); const [height, setHeight] = React.useState(window.innerHeight); const handleWindowResize = () => { setWidth(window.innerWidth); setHeight(window.innerHeight); }; React.useEffect(() => { window.addEventListener("resize", handleWindowResize); return () => window.removeEventListener("resize", handleWindowResize); }, []); /* Now we are dealing with a context instead of a Hook, so instead of returning the width and height we store the values in the value of the Provider */ return ( <viewportContext.Provider value={{ width, height }}> {children} </viewportContext.Provider> ); }; /* Rewrite the "useViewport" hook to pull the width and height values out of the context instead of calculating them itself */ const useViewport = () => { /* We can use the "useContext" Hook to acccess a context from within another Hook, remember, Hooks are composable! */ const { width, height } = React.useContext(viewportContext); return { width, height }; }; /* Make sure you also wrap the root of your application in the new ViewportProvider, so that the newly rewritten useViewport Hook will have access to the Context when used further down in the component tree. */ const App = () => { return ( <ViewportProvider> <AppComponent /> </ViewportProvider> ); }; const MyComponent = () => { const { width } = useViewport(); const breakpoint = 620; return width < breakpoint ? <MobileComponent /> : <DesktopComponent />; };

React Re-Render

+++ +++ React Re-render There are 2 common cases that we want to re-render Top Bottom Bottom up Top Bottom The common cases: data from current to child Triggers: Any change in current states (in setXXX method) Any change in props function ParentComponent() { return ( <div> <ChildComponent /> </div> ); } function Component() { { /*Internal state */ } const [myState, setMyState] = useState(0); return ( <div> <p>{"Number: " + myState.toString()}</p> {/* Any change of myState (is set by setMyState) will be trigger re-render */} <button onClick={() => setMyState(myState + 1)}>Click me</button> </div> ); } function ParentComponent() { const [countParent, setCountParent] = useState(0); const fromParent = "Count from Parent: " + countParent; return ( <div> <Component prefixText={fromParent} /> <button onClick={() => setCountParent(countParent + 1)}> Click me Parent </button> </div> ); } function Component({ prefixText }) { { /*Internal state */ } const [myState, setMyState] = useState(0); return ( <div> <p>{prefixText}</p> <p>{"Count from Child: " + myState.toString()}</p> {/* Any change of myState (is set by setMyState) will be trigger re-render */} <button onClick={() => setMyState(myState + 1)}>Click me Child</button> </div> ); } Bottom Top Use callback approach to raise event function JiraEditableTextField({ children, jiraRow, jiraField, onReRender }) { function handleEdit() { if (editting) { jiraRow[jiraField] = fieldValue; /* Create new object to notify the setter (setReRende) know this is a change */ onReRender({ render: true }); } setEditting(!editting); } const [editting, setEditting] = useState(false); const [fieldValue, setFieldValue] = useState(jiraRow[jiraField]); if (editting) { return ( <HStack> <Input type="text" value={fieldValue} onChange={(e) => setFieldValue(e.target.value)} ></Input> <IconButton size="sm" icon={<CheckIcon />} onClick={handleEdit} /> </HStack> ); } else { return ( <HStack> {children} <IconButton size="sm" icon={<EditIcon />} onClick={handleEdit} /> </HStack> ); } } function JiraCell({ jiraRow }) { const [reRender, setReRender] = useState({ render: false }); return ( <Card maxW="sm"> <CardHeader> <Grid templateColumns="repeat(4, 1fr)"> <GridItem mr={2}> <StatusColorDisplay status={jiraRow.status} /> </GridItem> <GridItem colSpan={2}> <Link href={jiraRow.link}> <Heading as="h3" size="sm"> {jiraRow.key} </Heading> </Link> <Text>{jiraRow.assignee}</Text> </GridItem> <GridItem> <Text>Due Date</Text> <Text>{"N/A" || jiraRow.duedate}</Text> </GridItem> </Grid> </CardHeader> <CardBody> <JiraEditableTextField jiraRow={jiraRow} jiraField="summary" reRender={reRender} onReRender={setReRender} > <Text size="sm" noOfLines={3}> {jiraRow.summary} </Text> </JiraEditableTextField> </CardBody> <CardFooter> <TagNameDisplay tagNameList={jiraRow.tagNameList} tagColor="green" textColor="white" /> </CardFooter> </Card> ); }

Run Local Docker for Frontend

+++ +++ Run in Local/Docker We can run directly from source or build the docker image Run from source Run by npm run npm run dev The above command will lookup scripts section "scripts": { "dev": "vite", "dev-host": "vite --host", "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "docker-dev-up": "docker-compose -f docker-compose.dev.yml up", "docker-dev-down": "docker-compose -f docker-compose.dev.yml down" } In the case we want to specify exposed port: npx vite --port=4000 Deploy/Run in Docker (Development environment) Create Dockerfile for example Dockerfile.dev for development only Expose port 5173 (for example) in docker container Run the conmand to allow on host machine CMD [ "npm", "run", "dev-host" ] The above command will refer to the command in scripts section in package.json "scripts": { "dev": "vite", "dev-host": "vite --host", # Follow the link: https://blog.vishnuprasaath.dev/dockerize-react-app-for-dev-and-prod FROM node:14-alpine as dev ENV NODE_ENV dev # set/create current working directory (on container docker machine) WORKDIR /tranlation-frontend # Cache and install dependencies COPY package.json . # Try to RUN npm config set strict-ssl false # RUN intall RUN npm i # COPY all app files COPY . . # Expose port EXPOSE 5173 # Start the app # CMD [ "yarn", "start" ] CMD [ "npm", "run", "dev-host" ] Build and create docker image and service by using docker-compose.yml Map host’s port with port’s docker (3000:5173 example) version: "3.8" services: app: container_name: translation-ui image: translation-ui-image build: context: . dockerfile: Dockerfile.dev volumes: - ./src:/tranlation-chakra/frontend/src - ./package.json:/tranlation-chakra/frontend/package.json - ./vite.config.js:/tranlation-chakra/frontend/vite.config.js ports: - "3000:5173" Deploy/Run in Docker (Production environment) In production we need to add new proxy server to handle request (load balancing,…). We can use nginx web server.