I've been working with react for years and I still have a simple question that I could never understand nor get the answer anywhere. Is calling an outside function in react component body bad?
For example:
import { getUser } from './helpers';
function MyComponent() {
const user = getUser();
return (
...
What will happen to user variable when component gets re-rendered by the parent component? Variables created in component body are created again in memory? Should I use useCallback or useMemo? I feel those two react functions are for other reasons, as expensive calculations and to prevent unecessary prop re-render.
To answer your first question in my experience I've never heard of calling outside functions within a react body as bad. In fact it's always been something that was encouraged especially for helper functions like in your example. There are definitely other ways to handle helper functions that may be needed multiple times (useContext comes to mind) but I don't see anything wrong with importing an outside function to call within a react body.
As far as what happens to user in your example it would get reset to the new return of getUser() upon any component re-render.
The user variable will be set to the value returned by getUser() on each re-render. And yet, getUser() will run on each re-render.
React Hooks are functions with use at the beginning of the function name, documented here.
Related
I read in an article that if you have some code like:
class Parent extends Component {
render() {
return (
<Child
onClick={() => console.log('You clicked!')}
/>
);
}
}
Child will be re-rendered every time Parent re-renders, even if there's no change in its props, only because the onClick function is inline and so it creates a new reference on every render.
However, even after moving that function outside of render(), Child re-rendered.. so what am i missing here?
In addition, that article also mentioned that inline functions increases a React app's memory footprint, since a new function reference is created on each render. Is that true? Doesn't JS have some sort of automatic garbage collection?
A couple of things, what you have posted only works for Class components, and as to why it works with Class components is that you are creating a callback function and binding it to the instance of the component, therefore each render of the component, it is the same callback function instance being used.
More reading on this https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/ under "Why don’t we need to bind ‘this’ for Arrow functions?"
For a function component, it's different, there is no class instance, you can use the useCallback hook that will memoize a callback, given a set of dependencies remain the same.
As someone pointed out in the comments you should only really aim to memoize callbacks etc though when they will prevent rerenders of large/deep children
I've been working on react native for the last 3 months, but i have no experience when it comes to building a website in just react. I would like to know if its possible to re-render the "index.js" file, after a certain function in a different file is called? I want to know if maybe i can do this through a useState variable, lets say "firstTimeLoading", that only calls that function when its true and then that said function changes that variables state to false, so that way that function is only called once. Is it possible to use this method? Is it the best choice here? And how do i pass that varaible to another file so i can change its state?
Ooh thats a tricky one, i'm not that great at redux but i think redux could solve that problem. However some tricks i used which aren't great is by emitting functions that change the state in the parent. In that way does the parent rerender and the childrens rerenders aswell.
function changeName() {
setState({name: "test"});
}
render(){
return(
<Child emitter={this.changeName} />
)
}
this way does the child call changeName with the help of props and the parent later calls its function since the function "changeName" is in the props to the child.
if you want to update the whole site could you simply use this terrible call:
window.location.reload();
I was facing multiple re-renders and thus to find the issue I commented every line of code and at last found the constant definition causing re-render:
const MyComponent = () => {
console.log('render') // logs 4 times
const myRef = useRef(null)
return <h1>hello</h1>
}
const MyComponent = () => {
console.log('render') // logs 2 times
return <h1>hello</h1>
}
I know strict mode renders the component 2 times. But, why just defining myRef constant causing re-render further 2 times?
I just tried React.memo as comment, but it still renders 4 times:
export default React.memo(MyComponent)
Okay, I just tested using the same code in App.js and it only logged 2 times. So, it seems to be parent component issue. But my question is why in the child component without having anything causing renders additional 2 times just defining the variable?
As you and React docs said:
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
Source: https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects
It does not include useRef but it actually should be on this list because it uses same underlying mechanism as useState
React.memo won't help here because what causes re-render is React.StrictMode special mechanism to check side effects and other stuff, so it ignores memo and similar techniques.
What's interesting here that if you add useRef in Parent component it will invoke function body 2 times, but its children (if they don't use useRef) are gonna be invoked only once.
All this stuff only works for development mode, so in production there won't be any intentional double invocations and other things but they can still happen unintentionally.
If declaring an arrow function inside a react class component is bad for performance,
why does declaring variables(arrow functions) inside a functional component have better performance?
The way React is now moving towards using the entire app with only functional components, won't it have performance issues for big apps that have long component trees with lots of variables that being redeclared on each update? (I know some are garbage collected but the declaration still occurs, same as using arrow function inside the render function of a class component)
class ReactComponent extends React.Component {
render() {
return (
<div onClick={() => console.log('do something')}>
<SomeOtherComponent onChange={() => console.log('pass function')} />
</div>
);
}
}
const functionalComponent = () => {
const doSomething = () => console.log('do something');
const passFunction = () => console.log('pass function');
return (
<div onClick={doSomething}>
<SomeOtherComponent onChange={passFunction} />
</div>
);
};
Nothing is "bad for performance", there are only unnecessary computations. If creating a function is necessary to express the behaviour of a program, there is nothing "bad". It is only "bad" if creating the function can be avoided, and it is even worse if a lot of computations can be avoided.
Creating a function is cheap. It creates a new function object, that contains a reference to the functions code as well as to it's environment (the "closure"), so a function expression is not much different than an object literal. Therefore creating functions is not "bad", and it never was.
The real problem that arises from function expressions in React, is not the function expression itself, but the logical result of it:
<div onClick={() => doStuff()}> Test </div>
On every rerender, a new function object gets created, that references a different environment, that might contain a different doStuff method, that might do something different. Therefore on every rerender, React has to detach the listener, and attach a new one referencing the new function, so that the new behaviour gets triggered. For one listener this is cheap, but if you pass down functions to other components, that pass down functions to other components, the cost multiplies (= more components have to rerender), so it might get expensive (= something we might worry about). If the function changes, but what it does does not, reattaching the listeners is uneccessary, and thus it can be avoided by making sure that functions only get recreated when the values they depend on get recreated:
const callback = useCallback(() => doStuff(), [doStuff]); // returns the same function, unless doStuff changes
<div onClick={callback}> Test </div> <- only gets reattached when doStuff changes
If declaring an arrow function inside a react class component is bad for performance
The reason people warn you about creating functions on every render is not because creating functions is slow. It's not; creating functions is very fast.
The performance issue comes when you pass that function to something else, and that something else is using shouldComponentUpdate or PureComponent or React.memo or useMemo or some other form of memoization. Since it received a new function, it thinks it needs to recompute, and so the memoization benefit is lost.
It's true that this issue can occur in function components too, but that's one of the things that useCallback and useMemo are for. You can use those hooks to create the function only once, and thus you will not needlessly break memoization of other components.
I'm building a <BasicForm> component that will be used to build forms inside my application. It should handle submit, validation and also should keep track of the inputs state (like touched, dirty, etc).
Therefore, it needs some functions to do all that and I've been wondering what is the best place to put those declarations (concerning code organization and performance optimization, considering React and JavaScript best practices).
I'm using React 16.8 hooks and bundling with Webpack.
So far, here's what I've got:
BasicForm.js
/* I moved those validating functions to a different file
because I thought they are helpers and not directly related
to my BasicForm functionality */
import { validateText, validatePassword, validateEmail } from './Parts/ValidationHelpers';
function BasicForm(props) {
const [inputs, setInputs] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
// These are functions to handle these events
function onChange(event) {...}
function onBlur(event) {...}
function onFocus(event) {...}
// This function creates the initial state for each form input
function setInputInitialState(inputProps) {...}
// This functions does what it name says
function validateAllFields() {...}
// This one also
function checkValidationAndSubmit() {...}
return(
<FormContext.Provider value={{
onBlur: onBlur,
onFocus: onFocus,
onChange: onChange,
inputs: inputs,
setInputInitialState: setInputInitialState
}}>
<form onSubmit={onSubmit} method='POST' noValidate>
{props.children}
</form>
</FormContext.Provider>
);
}
My question is: as you can see, up to this point, I'm declaring all the functions that my <BasicForm> uses (onChange, onBlur, onFocus, setInputInitialState, validateAllFields, checkValidationAndSubmit) inside the body of my BasicForm React component function.
Is this the best practice? If I was using classes those functions would probably be methods of my BasicForm class. But since I changed to hooks and got rid of most classes, I always have doubts about placing auxiliar functions inside or outside my React components function's body. Is there a best practice for this?
When the auxiliar function may need some variables or state from my main function, I could always pass them as parameters when I call them (if they are declared outside).
Do I gain or lose anything if I declare them outside of my BasicForm function? Keeping in mind that this is a module that gets bundled with Webpack.
If the function does not rely on props or state, then it is best to define it outside of your component function. If it does rely on props or state, then it generally makes sense to define it inside your component function, but if you are passing the function as a prop to a child component, then you should consider using useCallback (though this generally only adds value if the child component is memoized).
When the function depends on props or state, if you move the function out of the component and pass it arguments, you will end up needing to wrap that call in another function (e.g. ()=>helperFunc(prop1, someState)) in order to pass it as a prop to a child component. If the function is large, you may still want to pull it out of the component in that manner, but that just comes down to style preferences.
For more information on useCallback, see my answer here: Trouble with simple example of React Hooks useCallback