Using functions in react native render - javascript

I have 2 functions called isTrue and isFalse.
export function isTrue(param) {
return param === true;
};
export function isFalse(param) {
return param === false;
};
I have a few buttons in react native which change from disabled state want a variable is true or false. I could do it like this:
<Button
text="This is a button"
onPress={handlePress}
isDisabled={var === true}
/>
But now I'm using the functions like this:
<Button
text="This is a button"
onPress={handlePress}
isDisabled={isTrue(var)}
/>
When adding a console.log to the 'isTrue'-function, I see it gets called a lot (every re-render).
Is this bad for performance. I'm not seeing any performance issues, but it's quiet a simple app (for now) and I don't think the calculations in this function is't difficult.
I'm planning to add more functions like isNull, isNotNull. It's just for myself, var === null works like isNull(var) but for me it's easier to read. If there could be any performance issues, I switch back again.

It's fine. It's just how react works, you can't do anything about it and it's not a performance issue
But these particular functions don't do anything, you could just do
<Button
text="This is a button"
onPress={handlePress}
isDisabled={var}
/>
If something is true or false, you don't have to additionally compare them to true or false
const x = true
console.log(x, x === true)

Related

Should component itself prevent unwanted useEffect() calls?

Using useEffect() properly is sometimes not that easy. Imagine we have the following simple app using the Counter component:
import { useState, useEffect } from 'react';
const Counter = ({ onOdd, onEven }) => {
const [count, setCount] = useState(0);
useEffect(
() => {
console.log('Inside useEffect()');
if (count % 2 === 0) {
onEven(count);
} else {
onOdd(count);
}
},
[count, onOdd, onEven]
);
return (
<button
type="button"
onClick={() => setCount(count => count + 1)}
>
{count}
</button>
);
}
const App = () => {
const [isDarkMode, setIsDarkMode] = useState(false);
return (
<div style={{
backgroundColor: isDarkMode ? 'black' : 'white',
}}>
<Counter
onOdd={count => console.log(`Odd count: ${count}`)}
onEven={count => console.log(`Even count: ${count}`)}
/>
<button
type="button"
onClick={() => setIsDarkMode(isDarkMode => !isDarkMode)}
>
Toggle dark mode
</button>
</div>
);
}
export default App;
The app does two things:
It includes a Count button that increments its counter by 1. This components allows to inject two functions: onOdd and onEven. Whenever the counter changes, either onOdd or onEven is called, depending on the counter... being odd or even.
There is also a dark mode toggle. The only purpose I added it is to have something that causes the Counter to re-render for other reason than changing the count.
Now, the app works with one quirk - whenever we toggle the dark/light mode, the onOdd or onEven is being called. That's wrong, but understandable - we're creating new functions on each render, so useEffect() is being called.
I can think of 4 ways to fix this behavior:
Remove onOdd and onEven from useEffect() dependencies. It will fix the behavior, but it's considered a problem. The linter would complain about it, as we're losing data integrity. In theory, if we really change these callbacks, they should be re-run, right? That would be "the React way".
Move the callback functions outside of the App component:
const onOdd = count => console.log(`Odd count: ${count}`);
const onEven = count => console.log(`Even count: ${count}`);
const App = () => {
// ...
return (
// ...
<Counter
onOdd={onOdd}
onEven={onEven}
/>
// ...
);
}
This is a good and fast solution, but it's only possible because we don't use hooks or state inside these callbacks. What if we did?
Using useCallback() in App component:
const App = () => {
// ...
const onOdd = useCallback(
count => console.log(`Odd count: ${count}`),
[]
);
const onEven = useCallback(
count => console.log(`Even count: ${count}`),
[]
);
return (
// ...
<Counter
onOdd={onOdd}
onEven={onEven}
/>
// ...
);
}
Memoizing the callback functions in Counter component. If we had thousands of components using Counter component, it would still mean only one place to memoize these functions. I'm not sure if that makes sense though.
How do React gurus approach this problem? I wanted to keep the example as simple as possible, so option #2 will work perfectly and would probably be preferable. But what if we needed to keep these callbacks inside the App component?
Is it always the parent component responsible to memoize all callbacks it passes to the child? If so, is it a recognized pattern to always memoize all functions passed as props (and perhaps any other objects) with useCallback() or useMemo()?
I'm not properly a React Guru, but I consider all first three approaches to have their sweet spot, the 4th does not make sense. The only one to be careful with is the first one, since removing functions from deps, might lead to stale state issues, so if you know what you are doing, you may suppress lint warn ( I do that sometimes and know many others do that as it has been discussed extensiveley here https://github.com/facebook/react/issues/14920 ), otherwise it's better you avoid this approach.
The point number 2 is preferred everytime you have pure functions, always try to place your pure functions out of React components, inside some other folder like utils, misc, etc...
As per point number 3 that's the preferred way to handle functions declared inside React components, always memoize them with *useCallback* ( or useMemo if you need to perform calculations before to return a function ) , and there's nothing bad with doing that in the parent component. If you find yourself having dozens or hundreds of them and fear code pollution, consider that custom hooks let you to organize your code smartly, you could make a custom hook like useMemoizedHandlers inside your App component, where you create and memoize all your handlers and use it like:
const {
handler1,
handler2,
handler3
} = useMemoizedHandlers()
Options 2 and 3 are both absolutely valid and common, used interchangeably depending on whether the function has render cycle dependencies. Option 1 is a big no no. Option 4 is not really memoization at all - you can create stable references from functions passed as props but you cannot memoize the functions themselves as they've already been created anew.
Is it always the parent component responsible to memoize all callbacks it passes to the child?
In an application context I would say yes as this is the only way to enable React.memo on the consuming component's props. However, libraries will often convert functions to stable refs in the child, in case users forget to memoize themselves (or just as improved DX). Again, this is not the same as memoization, but it does mean that you can avoid the dependency issues highlighted in your question.
Is it a recognized pattern to always memoize all functions passed as props (and perhaps any other objects) with useCallback() or useMemo()?
You will find both memoization maxis and minimalists in the React community so it's hard to say that there's an accepted standard. Generally, you can get away with not doing it until you need it, like your example. However, purely from personal experience, once you do it a few times out of necessity it starts to become a habit as it reduces the possibility that bugs like this can occur.

Change handlers in react hooks

For a while a would like to start using react function components with react hooks instead of class extending react component, but there is one thing which discourages me. Here is an example from very first intro of react hooks:
import React, { useState } from 'react'
import Row from './Row'
export default function Greeting(props) {
const [name, setName] = useState('Mary');
function handleNameChange(e) {
setName(e.target.value);
}
return (
<section>
<Row label="Name">
<input
value={name}
onChange={handleNameChange}
/>
</Row>
</section>
)
}
There is a handleNameChange declaration used as a change handler for input. Let's imagine that Greeting component updates really really frequently because of some reason. Does change handle initialize every time on every render? From JavaScript aspect of view how bad is that?
Does change handle initialize every time on every render?
Yes. That's one reason for the useCallback hook.
From JavaScript aspect of view how bad is that?
Fundamentally, it's just creating a new object. The function object and the underlying function code are not the same thing. The underlying code of the function is only parsed once, usually into bytecode or a simple, quick version of compilation. If the function is used often enough, it'll get aggressively compiled.
So creating a new function object each time creates some memory churn, but in modern JavaScript programming we create and release objects all the time so JavaScript engines are highly optimized to handle it when we do.
But using useCallback avoids unnecessarily recreating it (well, sort of, keep reading), by only updating the one we use when its dependencies change. The dependencies you need to list (in the array that's the second argument to useCallback) are things that handleNameChange closes over that can change. In this case, handleNameChange doesn't close over anything that changes. The only thing it closes over is setName, which React guarantees won't change (see the "Note" on useState). It does use the value from the input, but it receives the input via the arguments, it doesn't close over it. So for handleNameChange you can leave the dependencies blank by passing an empty array as the second argument to useCallback. (At some stage, there may be something that detects those dependencies automatically; for now, you declare them.)
The keen-eyed will note that even with useCallback, you're still creating a new function every time (the one you pass in as the first argument to useCallback). But useCallback will return the previous version of it instead if the previous version's dependencies match the new version's dependencies (which they always will in the handleNameChange case, because there aren't any). That means that the function you pass in as the first argument is immediately available for garbage collection. JavaScript engines are particularly efficient at garbage collecting objects (including functions) that are created during a function call (the call to Greeting) but aren't referenced anywhere when that call returns, which is part of why useCallback makes sense. (Contrary to popular belief, objects can and are created on the stack when possible by modern engines.) Also, reusing the same function in the props on the input may allow React to more efficiently render the tree (by minimizing differences).
The useCallback version of that code is:
import React, { useState, useCallback } from 'react' // ***
import Row from './Row'
export default function Greeting(props) {
const [name, setName] = useState('Mary');
const handleNameChange = useCallback(e => { // ***
setName(e.target.value) // ***
}, []) // *** empty dependencies array
return (
<section>
<Row label="Name">
<input
value={name}
onChange={handleNameChange}
/>
</Row>
</section>
)
}
Here's a similar example, but it also includes a second callback (incrementTicks) that does use something it closes over (ticks). Note when handleNameChange and incrementTicks actually change (which is flagged up by the code):
const { useState, useCallback } = React;
let lastNameChange = null;
let lastIncrementTicks = null;
function Greeting(props) {
const [name, setName] = useState(props.name || "");
const [ticks, setTicks] = useState(props.ticks || 0);
const handleNameChange = useCallback(e => {
setName(e.target.value)
}, []); // <=== No dependencies
if (lastNameChange !== handleNameChange) {
console.log(`handleNameChange ${lastNameChange === null ? "" : "re"}created`);
lastNameChange = handleNameChange;
}
const incrementTicks = useCallback(e => {
setTicks(ticks + 1);
}, [ticks]); // <=== Note the dependency on `ticks`
if (lastIncrementTicks !== incrementTicks) {
console.log(`incrementTicks ${lastIncrementTicks === null ? "" : "re"}created`);
lastIncrementTicks = incrementTicks;
}
return (
<div>
<div>
<label>
Name: <input value={name} onChange={handleNameChange} />
</label>
</div>
<div>
<label>
Ticks: {ticks} <button onClick={incrementTicks}>+</button>
</label>
</div>
</div>
)
}
ReactDOM.render(
<Greeting name="Mary Somerville" ticks={1} />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
When you run that, you see that handleNameChange and incrementTicks were both created. Now, change the name. Notice that nothing is recreated (well, okay, the new ones aren't used and are immediately GC'able). Now click the [+] button next to ticks. Notice that incrementTicks is recreated (because the ticks it closes over was stale, so useCallback returned the new function we created), but handleNameChange is still the same.
Looking strictly from a JavaScript perspective (ignoring React), defining a function inside a loop (or inside another function that's called regularly) is unlikely to become a performance bottleneck.
Take a look at these jsperf cases. When I run this test, the function declaration case runs at 797,792,833 ops/second. It's not necessarily a best practice either, but it's often a pattern that falls victim to premature optimization from programmers who assume that defining a function must be slow.
Now, from React's perspective. It can become a challenge for performance is when you are passing that function to child components who end up re-rendering because it's technically a new function each time. In that case it becomes sensible to reach for useCallback to preserve the identity of the function across multiple renders.
It's also worth mentioning that even with the useCallback hook, the function expression is still redeclared with each render, it's just that it's value is ignored unless the dependency array changes.

React conditional onClick with ampersand

I want to edit a card if allowed=true. I came up with this solution:
const editCard = (onEdit, id, allowed) => {
if (allowed) {
onEdit(id);
}
};
<Card onClick={() => editCard(onEdit, id, allowed)}>Card</Card>
I thought of making a simpler onClick like so:
<Card onClick={() => allowed && onEdit(id)}>Card</Card>
Can I make on onClick like so with the ampersand? If allowed=true then edit, otherwise onClick should not do anything.
It seems to work but I don't know if it will always work. Can this cause bugs and is there a better way to implement this click event?
Yes, it will work as expected :)
true && something() calls something function
false && something() returns just false while not calling something
Yes, that will work. But you may also use like:
<Card allowed onClick={() => onEdit(id)}>Card</Card>
Then check the allowed props.
Just using allowed is equivalent to allowed={true}. If the allowed option is false you want to send, you don't need to pass the props.
But in your case, it's dynamic. So, you can use like:
<Card allowed={allowed} onClick={() => onEdit(id)}>Card</Card>
So, depending on the case it will be either allowed={true} or allowed={false}.
And oh, you want to use it in editCard, so you may just use like:
<Card onClick={() => onEdit(id, allowed)}>Card</Card>
A good use case with conditional statement would be to use like: (only show card if allowed is true)
{
allowed &&
<Card onClick={() => onEdit(id)}>Card</Card>
}
This way, you're ensuring clear instruction with your code. So, you found sorts of ways. Happy coding!

How to return an empty jsx element from the render function in react?

I have a code in react that looks something like this:
class UserManagement extends React.Component {
constructor() {
super();
this.state = {
users: undefined,
};
}
componentWillMount() {
// load the users state with a Promise
setTimeout(() => {
this.setState({users: []});
}, 800);
}
render() {
if ( this.state.users === undefined ) {
// until the users state is updated, I want to return an empty element
return null;
}
// real site rendering
return <div>We have users</div>;
}
}
ReactDOM.render(
<UserManagement />,
document.getElementById("root")
);
<div>Will be blank at first while we don't have users, then show "We have users" after 800ms when we have users</div>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
My question is: How to return an empty element until the users state is returned? I tried to return (null) as suggested in some places, but the browser raise this error:
Uncaught TypeError: Cannot read property 'style' of null
I am aware of the option to return (<div></div>), but I am not sure that this is the best practice in this case.
Thnaks!
Just in case anyone want another approach:
Since React v16.2 you can use Fragments allowing to add an empty JSX tag like this:
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
Example extracted from official docs.
So in your case, returning a Fragment without any childs, works.
return <></>;
I think just add { null } not null, in your section to show empty component.
Have you tried it already ?
Ok so as Facebook says :
Since React's release, people have been using work arounds to "render
nothing". Usually this means returning an empty or .
Some people even got clever and started returning to avoid
extraneous DOM nodes. We finally provided a "blessed" solution that
allows developers to write meaningful code. Returning null is an
explicit indication to React that you do not want anything rendered.
Behind the scenes we make this work with a element, though
in the future we hope to not put anything in the document. In the mean
time, elements do not affect layout in any way, so you can
feel safe using null today!
You need to wrap it in a React.Fragment tag.
<React.Fragment></React.Fragment>
use the react Fragment <></>. One of its advantages is that it does not create additional Dom nodes into rendered component (such as an empty div tag).
You can use ternary condition to make your code more readable.
render() {
( this.state.users === undefined ) ?
return <></>
: return <div>We have users</div>;
}
or oven simpler syntax would be
render() {
( this.state.users) ?
return <div>We have users</div>
: return <></>;
}
I think you should add ternary operators like:
this.state.users? return null : return <div>We have user<\div>
One thing I did using React.useState was to initialize an empty JSX.Element object like so
const [jsxObject, setJsxObject] = React.useState(<></>);
Then, in whatever function you want to return a JSX.Element
setJsxObject(<h1>whatever inside</h1>);
Render it in the component
{jsxObject}

Vuejs 2.3 - Sync and Element Ui Dialog

I'm using Element UI and things have changed since the release of Vue.js 2.3
I have a dialog that should be displayed only if the following condition is met private.userCanManageUsers && private.pendingUsers.length > 0 && private.pendingDialogVisible
I'm trying to use the new attribute visible.sync documentation here
It is working if the condition contains only one condition but does not work with several.
Working
<el-dialog
:visible.sync="private.pendingDialogVisible"
</el-dialog>
Not working
<el-dialog
:visible.sync="private.userCanManageUsers && private.pendingUsers.length > 0 && private.pendingDialogVisible"
</el-dialog>
What is the solution to use the el-dialog with visible.sync with
several condition?
If this is impossible what should I do to make it work ?
The issue is caused by a misunderstanding of what sync is actually doing.
In Vue 2.3 (unlike in Vue 1x), sync is nothing more than an event registration to facilitate two-way binding. Per the documentation:
In 2.3 we re-introduced the .sync modifier for props, but this time it
is just syntax sugar that automatically expands into an additional
v-on listener:
The following
<comp :foo.sync="bar"></comp>
is expanded into:
<comp :foo="bar" #update:foo="val => bar = val"></comp>
What does this mean in layman's terms? Since it is facilitating two-way binding to update the value being sync'd upon, you cannot use multiple properties (as a boolean expression), nor can you use the return value of a method since you must both read from and write to the same value.
In short, no, you cannot accomplish using sync in the way you are currently utilizing it and I personally disagree with the implementation that the library has chosen since it isn't particularly clear and forces complicated workarounds.
That said, you can use a single property for binding the visibility of :visible.sync and you can trigger that based on your state in the following example:
Template:
<div id="app">
<el-dialog title="Shipping address" :visible.sync="showDialog"
:before-close="beforeCloseHandler"
#close="cond1 = true; cond2 = false;">
</el-dialog>
<button #click="cond1 = true; cond2 = false; showDialog = true;">Open Dialog</button>
</div>
Javascript:
var Main = {
data() {
return {
showDialog: true,
cond1: true,
cond2: true,
};
},
methods: {
beforeCloseHandler: function (done) {
if (this.cond1 && this.cond2) {
console.log('hit close');
done();
} else {
console.log('rejected close');
}
}
}
};
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
We can bind the display to a single property and we can control dismissing with the :before-close handler and of course we can control our show conditions via a click event on a button. It isn't perfect, but it is a potential workaround.

Categories

Resources