Do React Hooks use more memory than Class Components? - javascript

My understanding is that Javascript classes store their methods on the Class prototype and therefore all Class instances use the same function definition in memory when invoking those methods. i.e. an single function definition in memory is used by every instance.
For React Hooks, a functional component can update state through the function returned by useState(). e.g.
import React, { useState } from 'react'
function MyComponent(){
const [greeting, setGreeting] = useState("Hello")
return <h1>{greeting}</h1>
}
If my application was to render 100 MyComponents, would the setGreeting() function in all 100 of the components refer to the same setGreeting() function in memory or would there be 100 copies of the same function in memory?

No, for 100 Components it will be 100 setGreeting would be created.SetGreeting is refrence to the function. So there will be 100 refrences.
Please refer below sandbox link: https://codesandbox.io/s/eager-kowalevski-x20nl
Explanation:
In below code I am storing references to setName function, just to verify whether it's same function or not. I am storing in two variables at window level. If the first variable is being stored, I store it in second one so that later I can compare. When I compare these two, they are different. Not a single occurence I get the console message saying "true". So each time a different function is being created.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("asutosh");
if (window.s1) {
window.s2 = setName;
} else {
window.s1 = setName;
}
console.log(window.s1 === window.s2);
return (
<div className="App">
<h1>Hello {name}</h1>
</div>
);
}

Related

how to calculate default value for react js state hook with a function?

I'm doing something like this:
function App() {
const [state1, setState1] = useState([1,1,1,1,1,1]);
const [state2, setState2] = useState(MyFunction());
return (
<div className="App">
<button onClick={() => setState1([1,2,3,4,5,6])}>test</button>
</div>
);
}
const MyFunction= () => {
alert("MyFunction");
return 5;
}
The strange thing is that the line alert("MyFunction"); is triggered 2 times on load and 2 times on every click on test button.
I'm very new to React.js and I don't understand this behavior.
To answer your question:
how to calculate default value for react js state hook with a function?
useState allows a function as a 'initial state factory', like e.g.:
const [ state, setState ] = useState( function(){ return Math.random(); } );
So if you want to use your MyFunction as a factory, just use it this way:
const [ state2, setState2 ] = useState( MyFunction );
why is MyFunction called on every click ?
A React functional component is just a javascript function.
React decides when to call this function, which is basically whenever something changes. A call of some setState() is one reason why
React will call the function of the functional component again (your App() function in this case).
But I suggest you consider the App() function to be called "whenever React wants to call it", or "all the time, again and again". Meaning you should not
rely on when the function of the functional component is called, you should instead rely on the guarantees which React makes
regarding when the state is up-to-date, specifically useEffect, useState, ...
MyFunction() is just a function call, which is inside the App() function call, so - of course - MyFunction() is called
whenever App() is called (which is "again and again").
Why is the alert() called twice ?
The functional component is called 2 times in Strict Mode.
This causes unexpected behavior only if you aren't using React as it is supposed to be used (which is something that just happens for React-beginners).
If you are using React in the intended way, you should not have to care about if the function is called once, twice or multiple times. The only thing that counts is what the state is.
See also e.g. React.Component class constructor runs once without console.log?

React (hooks) different value for refs on initial render

Can someone explain to me what is the reason for this situation!
Let's say I have a function which generates a random value on initial render. Then I assign the result using ref to keep the value unchanged after subsequent component updates.
After that I assign the ref value to some state. The state is initialized with the ref value inside setTimeout.
import React, { useRef, useState } from "react";
import value from "./example";
function App(){
const v = useRef(word());
console.log(v.current); // Here for example the value is "test"
setTimeout(() => {
console.log(v.current); // Here the value is different
}, 1000)
const [state, setState] = useState(v.current);
return (
<div>{v.current}</div>
)
}
I use setTimeout to illustrate the case but even without it the result is the same the state will be crated with different word although there is no component update.
How many times the component is render for the first initialization although there is no state change?
You are running your app in strict mode. Go to index.js and comment out the strict mode tag. You will find a single render.
This only applies to development mode. Lifecycles will not be double-invoked in production mode.
This is done by intentionally double-invoking the following functions:
https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects

Dynamic tag name

I'm trying to convert a dynamic tag naming system from React into a more hook like approach, what I'm doing is first I import and export a few components so that I can pull them all at once on a array, like this:
import Component1 from './Component1/Component1'
import Component2 from './Component2/Component2'
export {
Component1,
Component2
}
And then I load them like so:
import { useState, useEffect } from "react";
import * as Components from './../AllComponents/Components'
function importHook() {
const [states, setStates] = useState({
components: [],
currentComponent: 0
})
useEffect(() => {
Object.entries(Components).forEach(component => {
setStates(prevState => ({ components: [...prevState.components, component[1]]}))
})
}, []) // Look's into Components and adds every component to the 'components' array so that I can use that array in the next step.
return states;
}
export default importHook
And after that I proceed to do so:
import React from 'react'
import './MainComponent.scss'
import importHook from '../../importHook'
function MainComponent() {
const { components, currentComponent } = importHook() // Pull and set the values using the hook
const TagName = components[currentComponent] // Created the tag name by targeting the first function, seeing as currentComponent should be 0 at the time
console.log('Tag: ' + TagName) // undefined
return (
<div className="h-100">
<TagName /> // crashes everything
</div>
)
}
export default MainComponent
So I have figured out that the reason that <TagName /> crashes everything is because something runs twice.
If you remove <TagName /> so that you can get the output from console.log and change currentComponent inside the const TagName to 0, you notice that the first time console.log runs is returns undefined, while the second run returns the actual function that is stored inside the array.
So really my question is just, why / what executes twice? I have an idea, I'm assuming its because of the forEach that's adding to the array or something like that, but I'm not completely sure.
What can be done so that we can have all the values ready before returning here? I haven't tried this yet, but I assume I could introduce a if statement that would check and see if the variable is empty and if so, display some kind of loading screen or fidget, but this doesn't seem like the best solution to me, I know there are a lot of ways to do something but not all are good and since I'm really new to all of this its better to read / ask.
About the read part, couldn't find much about solving this or the implementation that I've mentioned, I have tried useEffect, useCallback and other such, not sure if I've been doing it wrong though...

Need code explanation Javascript for assigning a function to a constant

Hi i have the following React-Redux based code snipped and dont understand the following line:
const List = connect(mapStateToProps)(ConnectedList);
I would understand that a function is assigned to the List constant if it would look like:
const List = connect(mapStateToProps);
But what effect has the (ConnectedList) in this statement and what is the technical name of that what happend?
Full Snipped:
import React from "react";
import { connect } from "react-redux";
const mapStateToProps = state => {
return { articles: state.articles };
};
const ConnectedList = ({ articles }) => (
<ul className="list-group list-group-flush">
{articles.map(el => (
<li className="list-group-item" key={el.id}>
{el.title}
</li>
))}
</ul>
);
const List = connect(mapStateToProps)(ConnectedList);
export default List;
connect(...) returns a function (as you already realized), so connect(...)(ConnectedList) calls the function returned by connect() with ConnectedList as its argument.
The longer version of this would be:
const tmp = connect(mapStateToProps);
const List = tmp(ConnectedList);
Since you asked for the technical name: Usually a function returning another function is called a higher-order function.
connect(mapStateToProps);
Returns a high order React component(HOC). In this case, connect will inject the state you are mapping on the mapStateToProps pure function.
The purpose of a HOC is to compose another component, that's why you need the second part:
connect(mapStateToProps)(ConnectedList);
The HOC returned by connect() will add the props to the ConnectedList component.
You can see the docs here: connect documentation
connect() return an higher-order-component (component that wraps a component).
This function is responsible to subscribe to changes in your application's redux store, and whenever a change in store detected, it will call the mapStateToProps function you provided, passing the new store state to that function.
The value returned from mapStateToProps will then be pass to the component you are wrapping as props.
This makes the components connected to the redux store, and hence the name of it.
By the way, I would name the component you are wrapping as List, and the component returned from the connect() function as the ConnectedList.

Is it possible to pass context into a component instantiated with ReactDOM.render?

TL;DR Given the following example code:
ReactDOM.render(<MyComponent prop1={someVar} />, someDomNode);
Is it possible to manually pass React context into the instance of MyComponent?
I know this sounds like a weird question given React's nature, but the use case is that I'm mixing React with Semantic UI (SUI) and this specific case is lazy-loading the contents of a SUI tooltip (the contents of the tooltip is a React component using the same code pattern as above) when the tooltip first displays. So it's not a React component being implicitly created by another React component, which seems to break context chain.
I'm wondering if I can manually keep the context chain going rather than having components that need to look for certain data in context AND props.
React version: 0.14.8
No. Before react 0.14 there was method React.withContext, but it was removed.
However you can do it by creating HoC component with context, it would be something like:
import React from 'react';
function createContextProvider(context){
class ContextProvider extends React.Component {
getChildContext() {
return context;
}
render() {
return this.props.children;
}
}
ContextProvider.childContextTypes = {};
Object.keys(context).forEach(key => {
ContextProvider.childContextTypes[key] = React.PropTypes.any.isRequired;
});
return ContextProvider;
}
And use it as following:
const ContextProvider = createContextProvider(context);
ReactDOM.render(
<ContextProvider>
<MyComponent prop1={someVar} />
</ContextProvider>,
someDomNode
);
In React 15 and earlier you can use ReactDOM.unstable_renderSubtreeIntoContainer instead of ReactDOM.render. The first argument is the component who's context you want to propagate (generally this)
In React 16 and later there's the "Portal" API: https://reactjs.org/docs/portals.html

Categories