{"id":420,"date":"2019-07-24T15:44:38","date_gmt":"2019-07-24T15:44:38","guid":{"rendered":"https:\/\/jmrowe.com\/blog\/?p=420"},"modified":"2021-02-09T16:35:39","modified_gmt":"2021-02-09T16:35:39","slug":"miscellaneous-react-js-notes","status":"publish","type":"post","link":"https:\/\/jmrowe.com\/blog\/miscellaneous-react-js-notes\/","title":{"rendered":"Miscellaneous React js notes"},"content":{"rendered":"<p><strong>useEffect Notes<\/strong><\/p>\n<p>useEffect is called on initial load and every update after unless an empty dependency array is entered.. then it is only performed on first load:<\/p>\n<pre class=\"lang:default decode:true\">useEffect(()=&gt;{\r\n\/\/this will only be performed on first load\r\n},[]);\r\n\r\n\r\nuseEffect(()=&gt;{\r\n\/\/this will only be performed on first load and everytime \r\n\/\/ someVariableThatHasChanged has been updated\r\n},[someVariableThatHasChanged]);<\/pre>\n<p>&nbsp;<\/p>\n<p>For ajax calls on initial loads or in useEffect in general..async\/await is only allowed if done in this way:<\/p>\n<pre class=\"lang:default decode:true \">\/\/below is allowed\r\nuseEffect(()=&gt;{\r\nasync function getData(){\r\n\/\/get ajax data\r\n}\r\nlet returnedData=await getData();\r\n});\r\n\r\n\/\/ Having async in the way below is not allowed.\r\n\r\nuseEffect(async ()=&gt;{\r\nlet returnedData=await getData();\r\n});\r\n<\/pre>\n<p><strong>useEffect &amp; setState<\/strong><\/p>\n<p>useEffect generally would get the &#8220;stale&#8221; state value however we can pass in a callback to the setState function in order to recieve\/use the previous states value<\/p>\n<pre class=\"lang:default decode:true \">useEffect(()=&gt;{\r\n\/\/normally using setState as below wouldn't work \r\n\/\/because the actual value in someState is \"stale\"\r\nsetSomeState(someState+1); \/\/ will always return 1 because the stale someState would be it's initial value of 0\r\n\r\n\/\/below would work because the callback provides the actual previous state value\r\n\r\nsetSomeState(someState =&gt;someState+1);\r\n\r\n\r\n},[someState]);<\/pre>\n<p>&nbsp;<\/p>\n<p>The remaining problem with this is that you can only access the previous state value if you are setting (setSomeState) it. One work around that is provided is to use Refs<\/p>\n<p><strong>Using useRefs for current state value in useEffect<\/strong><\/p>\n<p>Refs exist outside of the re-render cycle and there for their actual current value isn&#8217;t effected by re-renders and so the value at ref.current will stay &#8220;current&#8221;. So the ref.current value will be what it was set last and not being reset or altered by a re-render. However, refs aren&#8217;t reactive.<\/p>\n<pre class=\"lang:default decode:true\">function Timer() {\r\n    const [count, setCount] = React.useState(0)\r\n    const countRef = React.useRef(0)\r\n\r\n    React.useEffect(() =&gt; {\r\n        const intervalId = setInterval(() =&gt; {\r\n            countRef.current = countRef.current + 1\r\n            setCount(countRef.current) \/\/ we don't need the call back to reference\r\n  \/\/ the previous state in order to update it properlly because we use ref.current which \r\n  \/\/ retains it's value and isn't affect by the re-renders.\r\n        }, 1000)\r\n        return () =&gt; clearInterval(intervalId)\r\n    }, [])\r\n\r\n    return (\r\n        &lt;div&gt;The count is: {count}&lt;\/div&gt;\r\n    )\r\n}<\/pre>\n<p>The problem with this approach is that refs aren&#8217;t reactive and so shouldn&#8217;t be used like how &lt;div&gt;The count is: {count}&lt;\/div&gt; is displayed because the actual value that is <strong>displayed<\/strong> (the counting would still happen behind the scene tho ) won&#8217;t update until the component is re-rendered.<\/p>\n<p><strong>React Router<\/strong><\/p>\n<p>Import react-router-dom to use for web. Wrap &lt;BrowserRouter&gt;&lt;\/BroswerRouter&gt; around &lt;App\/&gt; in the index.js<\/p>\n<p>To create routes you would do the following:<\/p>\n<pre class=\"lang:default decode:true\">&lt;Route exact path=\"\/\" component={TestComponent} \/&gt;\r\n&lt;Route exact path=\"\/test2\" component={TestComponent2} \/&gt;\r\n&lt;Route exact path=\"\/test3\" component={TestComponent3} \/&gt;\r\n&lt;Route exact path=\"\/test4\" component={TestComponent4} \/&gt;\r\n\r\n\/\/ this is inclusive so any  and all patterns match will be included if \"exact\" \r\n\/\/ keyword isn't used.\r\n\r\n\/\/ Can also wrap all of the routes in a &lt;Switch&gt;&lt;\/Switch&gt; component\r\n\/\/ and that will render only the FIRST to match the pattern exclusively<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Link vs NavLink<\/strong><\/p>\n<p>To link to a route you can use Link or NavLink. The difference mostly is that Link will just create a &lt;a&gt; element pointing to the route ( which doesn&#8217;t actually issue a GET request like a link normally would ). Navlink will do the same thing but it is to be used in menus because you can set a prop in Navlink to indicate the &#8220;active&#8221; route so it can be styled properly.<\/p>\n<pre class=\"lang:default decode:true \">&lt;Link to=\"\/\"&gt;Test1&lt;\/Link&gt; \/\/ creates simple &lt;a&gt; to route\r\n\r\n&lt;NavLink to=\"\/\" activeClassName=\"active-route\"&gt;Test1&lt;\/NavLink&gt;\r\n\r\n\/\/ above will put a class of active-route on the link it produces\r\n\/\/ so it can be styled different using CSS and classes\r\n\r\n\r\n&lt;NavLink to=\"\/\" activeStyle={{ color:'red' }}&gt;Test1&lt;\/NavLink&gt;\r\n\r\n\/\/ activeStyle is a inline prop where you can specify what\r\n\/\/ css should be applied if it is the active route.<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Passing a prop to a route ( render vs component props )<\/strong><\/p>\n<pre class=\"lang:default decode:true\">\/\/ below will pass a prop to the route but it is the wrong \r\n\/\/ way of doing so because the component will be recreated\r\n\/\/ every time going through the whole life cycle\r\n\r\n&lt;Route exact path=\"\/\" component={()=&gt;&lt;TestComponent name=\"jason\"\/&gt;} \/&gt;\r\n\r\n\/\/ we can prevent the needless re-render by using render instead:\r\n\r\n&lt;Route exact path=\"\/\" render={()=&gt;&lt;TestComponent name=\"jason\"\/&gt;} \/&gt;\r\n\r\n\/\/ this will make it so the component isn't needlessly re-rendering.<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>URL Parameters with Router<\/strong><\/p>\n<p>When a route is declared and component\/render\/children is used, 3 things are passed to component\/render\/children under one component.. &#8212; history, location , match<\/p>\n<p>So we can do the following to extract the parameter in a given route<\/p>\n<pre class=\"lang:default decode:true \">&lt;Route exact path=\"\/:name\" \r\nrender={(routeProps)=&gt;\r\n&lt;TestComponent name={routeProps.match.params.name\/&gt;} \/&gt;\r\n\r\n\/\/ in path, :name is the parameter for the route\r\n\/\/ when using render\/children\/component a route prop is\r\n\/\/ supplied (in our case it's called routeProps) with \r\n\/\/ the parameters available under\r\n\/\/ routeProps.match.params.name<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Redirects<\/strong><\/p>\n<p>Can use Redirect component from react-router-dom .<\/p>\n<pre class=\"lang:default decode:true \">\/\/ Simply doing below  will bring the user to the route for '\/'\r\n\r\n&lt;Redirect to='\/' \/&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Redirect programmatically\u00a0<\/strong><\/p>\n<p>This is done by pushing on the browser history stack. In order to be able to do that, the routeProps has to be passed down when the &lt;Route\/&gt; is created. This is done automatically if using componenet={SomeComponent} but needs to be passed manually if done via render instead. i.e. You would only need to use render if you want to pass other props to the Route&#8217;s component.<\/p>\n<pre class=\"lang:default decode:true \">props.history.push('\/') \/\/ will bring to base url\r\n\r\n\/\/ this will only work if you pass in route props.. \r\n\r\n\/\/i.e. when defining the route\r\n\r\n&lt;Route path=\"\/\" render={(routeProps)=&gt;{&lt;SomeComponent {...routeProps}\/&gt;}}\r\n\r\n\/\/ now you can push to the routeProps history\r\n\/\/ since SomeComponent has routeProps passed to it.\r\n\/\/ and it will bring you to '\/'\r\n\r\n\/\/ NOTE - if you use component instead of render then\r\n\/\/i.e.\r\n&lt;Route path=\"\/\" component={SomeComponent}\/&gt;\r\n\r\n\/\/ routeProps is already passed in and can be used\r\n\/\/ to push on history\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Some differences of history.push vs &lt;Redirect&gt;<\/strong><\/p>\n<p>&lt;Redirect \/&gt; won&#8217;t change the back button so if you redirect to a url that goes to a 404 then hitting the back button won&#8217;t bring them back to the url that will re-redirect to the 404 page. history.push will make the back button to the route that was pushed &#8211; so, if history.push to a route that goes to a 404 then hitting the back button will bring it back to the route that took it to the 404 and will be a endless loop.<\/p>\n<p><strong>Redirecting via history.push when the component has no route its self and so no routeProps &#8211; use withRouter<\/strong><\/p>\n<pre class=\"lang:default decode:true \">import React from 'react';\r\nimport {withRouter} from 'react-router-dom';\r\n\r\nconst RandomPropThatHasNoRoute=(props)=&gt;{\r\nreturn (&lt;button onClick={e=&gt;{props.history.push('\/newPage');}} &gt; Click to redirect &lt;\/button&gt;\r\n}\r\n\r\nexport default withRouter(RandomPropThatHasNoRoute);\r\n\r\n\/\/ the history push will only work if withRouter is set as above \r\n\/\/ because otherwise this componenet that has no &lt;Route\/&gt; will not\r\n\/\/ be given the routeprops(history).<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>props.history.goBack() and props.history.goFoward()<\/strong><\/p>\n<p>These methods are available if needed to create functionality in the app similiar to the browsers forward and back button.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>React Context API<\/strong><\/p>\n<p>Components can easier share values\/functions by being wrapped in a Context.Provider component. Any component that uses that particular Context will be re-rendered when that Context&#8217;s value changes. This may cause un-wanted re-renders.<\/p>\n<p>An example of using the Context Hook:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ in a seperate file (context.js) we initialize the context\r\n\r\nimport React from 'react';\r\n\r\nexport const todoContext=React.createContext();\r\n\r\n\/\/ then in container components or App.js\/index.js we can \r\n\/\/ wrap other components with the created context provider and pass\r\n\/\/ along objects to any children components so that the\r\n\/\/ values are available\r\n\r\n\/\/ App.js\r\n\r\nimport React from 'react';\r\nimport ReactDom from 'react-dom';\r\nimport {todoContext} from '.\/contexts.js'\r\nconst App=()=&gt;{\r\n\r\nreturn (\r\n&lt;&gt;\r\n&lt;h1&gt;Main App&lt;\/&gt;\r\n&lt;todoContext.Provider value={{count:100}}&gt; \/\/now count is available in \r\n                                           \/\/ child component(s)\r\n  &lt;ChildComponent1 \/&gt;\r\n  &lt;ChildComponent2 \/&gt;\r\n&lt;\/todoContext&gt;\r\n\r\n&lt;\/&gt;\r\n)\r\n}\r\n\r\nconst rootElement = document.getElementById(\"root\");\r\nReactDOM.render(&lt;App \/&gt;, rootElement);\r\n\r\n\/\/ then in the child component you can consume the value(count) via:\r\n\/\/ Childcomponent1.js\r\n\r\nimport React from 'react';\r\nimport todoContext from '.\/contexts.js';\r\n\r\nconst ChildComponent1=()=&gt;{\r\n\r\n\/\/ we retrieve and deconstruct the value object to extract count\r\nconst {count}=React.useContext(todoContext); \r\n\r\nreturn (&lt;p&gt; Showing the count retrieved from Context {count} &lt;\/p&gt;)\r\n}\r\nexport default ChildComponent1;\r\n\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>One issue with above is the todoContext using an object for the values ( values={{count:100}} ) , this will cause needless re-renders because the object will be rebuilt every time.<\/p>\n<p><strong>Setting Disabled attribute based on a function (computed property) that returns a boolean\u00a0<\/strong><\/p>\n<pre class=\"lang:default decode:true\">\/\/ validateNames is the function we want to run to check if 2 state vars \r\n\/\/ are set and return true or false based on that.\r\n\r\nconst validateNames = () =&gt; {\r\n    if (pluginMeta.className != \"\" &amp;&amp; pluginMeta.nonceName != \"\") {\r\n      return false;\r\n    } else {\r\n      return true;\r\n    }\r\n  };\r\n\r\n\/\/ we use validateNames in a ternary to create an object \r\n\/\/ containing disabled if validatesNames returns true \r\n\/\/ it will return an empty object ( not disabling) if false\r\n\r\n\r\nlet disabled = validateNames() ? { disabled: \"disabled\" } : {};\r\n\r\n\/\/ finally, we spread the disabled variable as below which\r\n\/\/ will either add the disabled attribute or nothing ( empty object )\r\n\r\n&lt;Button onClick={handleCloseModal}   {...disabled}&gt;Finished&lt;\/Button&gt;\r\n        \r\n      \r\n      \r\n        \r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Conditionally show a component based on a state array not being empty.<\/strong><\/p>\n<p>Casting the input.Values.length as a Boolean enables this to be possible. Without casting , it would return a 0 to the screen which is not what is desired.<\/p>\n<pre class=\"lang:default decode:true \">{inputValues &amp;&amp; Boolean(inputValues.length) &amp;&amp; (\r\n        &lt;&gt;\r\n          &lt;p&gt;This will only show if the array exists and isn't empty.&lt;\/p&gt;\r\n        &lt;\/&gt;\r\n)}<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>useEffect Notes useEffect is called on initial load and every update after unless an empty dependency array is entered.. then it is only performed on first load: useEffect(()=&gt;{ \/\/this will only be performed on first load },[]); useEffect(()=&gt;{ \/\/this will only be performed on first load and everytime \/\/ someVariableThatHasChanged has been updated },[someVariableThatHasChanged]); &nbsp; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-420","post","type-post","status-publish","format-standard","hentry","category-javascript"],"_links":{"self":[{"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/posts\/420","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/comments?post=420"}],"version-history":[{"count":26,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/posts\/420\/revisions"}],"predecessor-version":[{"id":702,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/posts\/420\/revisions\/702"}],"wp:attachment":[{"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/media?parent=420"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/categories?post=420"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jmrowe.com\/blog\/wp-json\/wp\/v2\/tags?post=420"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}