I am reading through the internet trying to find some performance resolute or preferred method of declaring static data, variables in react so I would like to hear your opinion.
This goes for react stateless and class components.
Let’s say I have an array with colors that I want to use somewhere inside React return().
const colors = ["red, "green", "blue"];
1) Declare it inside of render()
I suppose this is not preferred, snce it will be recreated on every render.
2) Declare it in constructor as a global variable
this.colors = ["red, "green", "blue"];
Nice, but maybe not preferred in some cases to have global variables.
3) Declare it as a return of function placed inside React component but outside of render(). We call the function from React return()
4) I think I saw somewhere using defaultProps.
Is there a best practice?
Few common approaches are to
declare it above a class or in beginning of a file after imports
if its a file specific constants.
const CONST1 = [0,1,2,];
class xxx extends yy {
....
}
or you can keep it in seperate file and import it when its common to many places.
something like
a json file
file a.json
{
"color": "red"
}
usage b.js
import constant from 'constants/a.json';
console.log(constant.color);
or even in global.color = 'red' which i would not advice to use
For class components, I've used the approach of declaring static variables on the class recently.
import React from 'react';
class Example extends React.Component {
// never changes, but may be used in other places, such as parent components
static displayName = 'Example';
state = {
someStateData: 'World'
};
render() {
const { someStateData } = this.state;
// do work
return <p>Hello {someStateData}</p>;
}
}
export default Example;
Well, I think it depends on your needs, most cases 2 and 3 might be enough. I've seen several proyect sources (such as create-react-app, react-native-maps, for instance) and they all handle this consts and "Global resources" in a same way:
They put them in separated files, and they import them as modules in every file where they are needed. I've used this approach and I can tell you is a really good and common practice
I want to bring up this because it's a really good thing:
https://www.npmjs.com/package/reactn
ReactN is a extension of React that includes global state management. It treats global state as if it were built into React itself -- without the boilerplate of third party libraries.
You can use [ global, setGlobal ] = useGlobal() to access the entire global state object.
It works in class, function, and non-react files.
I use it since 2 or 3 years ago, without a glitch.
I know that, given the OP's question, this is overkill. But anyway, I wanted to draw attention into this excellent tool.
Related
I am using react-navigation without redux. so i have two tabs each with their own stack navigator, having one screen each. so i need and array of locations in both screens. currently i am doing this in both screens:
state = { locations: [] };
componentDidMount() {
this.getAllLocations();
}
async getAllLocations() {
let locations = await this.getMoviesFromApi();
this.setState({ locations });
}
i just want to have this array at one location and both components should share this single source of truth. so changes made by either screen is reflected in the other screen. Is this possible without redux?
RN 0.59 has opened great possibilities with its release. One of them are react hooks, which is available in the latest version... in the future react hooks will be used everywhere. Trust me. So, a while back I looked for the possibilities of having a global state using react hooks and found the reactn library. It uses react native hooks, and even you can use global state in CLASS components. which opens a new door for theming and sharing data. Now my app supports light/dark mode, dynamic font size, Languages, and early implementation of "portals" using only this library.
The best part about it is that you can use it like state. There is no need of provider, or redux stuff (although it provides it). It can be integrated with react navigation (it requires modifying some source code, at most, adding an "n" to react, and reference the global variable). Is awesome and I love it.
I have been thinking in doing an article on medium about this, because the lib is not that popular in RN community, but hope that you will give it a chance the library is only 22KB, less than one full component.
As an alternative, you could think about writing your own library using hooks. But it's gonna be hard. Try it, there is no going back
It is possible if you have a singleton object :
export default class SharedData {
constructor(){
if(SharedData.instance){
return SharedData.instance;
}
this.state = {locations:[]};
this.listners =[];
SharedData.instance = this;
return SharedData.instance;
}
setLocations(locations){
this.state.locations = locations;
this.listners.forEach(listner=>listner(this.state.locations));
}
getLocations(){
return this.state.locations;
}
addListner(listner){
this.listners.push(listner);
return listner;
}
removeListner(listner){
let index = this.listners.indexOf(listner);
if(index > -1){
this.listners.splice(index,1);
}
}
}
and then in every tab where you want to access shared locations state:
// get an instance of SharedData
this.sharedData = new SharedData();
// subscribe to locations changes
this.listner = sharedData.addListner((locations)=>{
this.setState({locations});
});
// set locations
this.sharedData.setLocations([]);
// unregister when destroying the component
this.sharedData.removeListner(this.listner);
I guess in order to achieve your goal, you're going to need some sort of a mechanism for storing 'global data', and if you don like Redux because it requires a lot of setup to achieve this simple task of sharing global data, then you chould you unstated ... which is alot simple to setup
I see this code pattern a lot in React code:
render() {
const units = this.props.units;
const temperature = this.state.temperature;
return (<p>{temperature} {units}</p>);
}
and some developers I've asked say that its standard practice to pull state/props into local constants before using them in render or other functions - however, I can't find this practice discussed anywhere in the React docs, and the example code in those docs sometimes just access state/prop attributes directly.
I would prefer to use direct access because it makes the code more readable when you can immediately see where attributes are coming from instead of having to hunt down the local constant definitions.
Before I make this decision though, I was wondering if anyone knew why this practice exists and if there are good reasons to use it?
Is there a functional difference between the example above and this?
render() {
return (<p>{this.state.temperature} {this.props.units}</p>);
}
Its a standard practice to pull state/props when there a MANY props/state that are going to be used inside your functions
eg: const { prop1, prop2, prop3, prop4, ... } = this.props
const { state1, state2, state3, ... } = this.state
You can now reference them with the const names instead of
this.props.propName/stateName everywhere.
You shouldn't do that in the example you provided where there is just 1/few props/state
const units = this.props.units; // Not recommended
Bottomline : Just cleaner code. Matter of preference.
The reason why we need to get constants from props is to destructure the props object. Destructuring means your getting a property of the props object. With that you can lessen the code needed instead of using this.props.yourProps when you destructure it. It wil only be yourProps instead.
Also your destructure should be on es6 for es6 standards: Use
const {units} = this.props; //This gets the key units from the props object (es6 Syntax)
Instead of
const units = this.props.units; // This does the same but without using the es6 syntax
If you Structure your code in this manner you can write less code and can maintain it better... When we follow standards like this we won't worry even the organization switches from one developer to another.
The following component displays some static data.
What is the idiomatic way to store static data that is local to components?
Is it fine as I have done to store the data in a module scoped variable called data?
Or should I do something else like perhaps creating a ./data.json file that I import?
import * as React from 'react';
import SectionContainer, {
InnerSectionContainer,
FlexContainer,
FlexItem
} from '../../ui/SectionContainer';
import ScaledImage from '../../ui/ScaledImage';
import { SectionHeading } from '../../ui/Headings';
const data = {
title: 'Trusted by',
imageSrcs: [
require('../../../images/logo1.png'),
require('../../../images/logo2.png'),
require('../../../images/logo3.png')
]
};
const Logos = () => {
const logoItems = data.imageSrcs.map((imageSrc, index) => {
return (
<FlexItem key={index}>
<ScaledImage src={imageSrc} />
</FlexItem>
);
});
return (
<SectionContainer>
<InnerSectionContainer>
<SectionHeading>
{data.title}
</SectionHeading>
<FlexContainer>
{logoItems}
</FlexContainer>
</InnerSectionContainer>
</SectionContainer>
);
};
export default Logos;
I usually have one or more consts.js file(s) on my codebase.
If it's static, needs to be on the frontend and is used to just ONE component, I just put it along with the component's own file.
If it's being used by a few components under the same component structure (say, a component that solves a particular problem, that has some sub-components, but the static information is not relevant to any other component outside of this scope), I'd create a consts.js file on that component tree.
And if it's something that's going to be used by everyone, say, a set of style colors that reactjs is going to need for some reason, just create a global consts.js file and import as needed.
That being said, it's just how I use it. You can create your own approach. Try, experiment, and use what seems to work best for you.
EDIT:
I just saw this part of your code:
const data = {
title: 'Trusted by',
imageSrcs: [
require('../../../images/logo1.png'),
require('../../../images/logo2.png'),
require('../../../images/logo3.png')
]
};
This approach will work on a javascript file type like consts.js, like I mentioned above, but NOT on a json file, since you can't use require inside them (all data is static. there is no logic or imports).
You should tend towards declaring static data as close as possible to where it will be used. In other words, in the smallest scope that makes it visible to the code that needs it.
In javascript, then, if the data is needed:
by one function, declare it in the function
by one file, declare in the file
by the methods of an object/class/component, declare as a static or instance property in the class
by users of a class or object declaration, then also as a class static
by several components of a package, then in utils.js (or similar) file
by many classes/components, declare and export from a file in a "common" or "library" package
I wouldn't quibble about how you structured your example; it's perfectly fine. Putting that data into its own .js file is unnecessary unless you know for sure it will be used by at least one other component. Even then, if that other component also needs your Logos component, then exporting from where it is now would be fine.
When deciding about how to structure things, I think the first consideration should be: how can I make it easiest, for a future reader of my code, to figure out what I have done.
I have a component that has grown rather large. I decided to break it up into two components, but have found that the component I have split off needs to utilize a method from the original component.
What is the best way to consume a method from inside of an existing component?
Thanks in advance!
Once upon a time, one would have used mixins to achieve what you are looking to do. Since then, this article came out : https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html
They are still an option in my opinion but require discipline so that you don't overuse the concept.
Other options for you would be:
a) Bring the desired method up one level. By that I mean you could declare it in the container component and pass it along a props to the 2 childrens.
b) If the method is generic enough, declare it in an utility class that you would import in both components. (using static is an option as well)
c) any other innovative way ;) (just to say that these are not the only options)
Extend your base class with in a Split off version. If you use ES6 it would look something like this:
class Base extends React.Component {
renderText () { return 'Hello'}
render(){
return <span>{this.renderText()}</span>
}
}
class SplitOff extends Base {
render() {
return <span>{`${this.renderText()} World`}</span>
}
}
JSFiddle of the above
Setup:
BabelJS (es2015, react, stage-1)
Webpack
React / redux
New to CommonJS and ES6. I know the difference between an object instance and a static container of methods but I am not sure how they behave when separated to modules. So I wonder what are the differences between returning an instance (is this pattern valid at all?):
// StateParser.js
class StateParser {
constructor() {
}
method1() {
...
}
}
export default new StateParser()
and exporting const methods:
// StateParser.js
let state = {
}
export const method1 = () => { ... }
Method A: Would there be a new instance every time I import?
Method B: Is one of the benefits the ability to use object destructuring:
import { method1 } from '../utils/StateParser.js';
and then use method1 as if it existed locally?
Method A: Is one of the benefits the ability to initialize state in the constructor?
So basically I am not sure when to use which for my utility classes and would appreciate your input.
Would there be a new instance every time I import A?
No, modules are only evaluated once.
Is one of the benefits of B the ability to use object destructuring and then use method1 as if it existed locally?
Yes, though it's not called "destructuring". They're named imports (or named exports of the module), and they don't nest and use a different syntax for aliasing.
Is one of the benefits of A the ability to initialize state in the constructor?
No. You can initialise module state just directly in the module scope as well, you don't need a constructor function for that.
But yes, if you have state in the instances, it's a good idea to use a class which you can instantiate multiple times. For that, you need to export the class itself, not an instance, of course.
Is the export default new … pattern valid at all?
No, it's an antipattern for the reasons outlined above. Given the class is used nowhere else, it's quite similar to the anonymous class antipattern. And exporting multiple named exports is much better than default-exporting objects anyway.
We don't recommend exporting an evaluation (e.g. new StateParser()) for several reasons.
In this case, the module exports the result which is only evaluated once (also mentioned by #Bergi). This is rarely the desired outcome, but if it is, a Singleton pattern should be used instead. Some ES6 module benefits are lost (tree-shaking and faster access to imports), it makes imports slower and makes them possible to cause side-effects which should rather happen upon invocation. I also think this is an anti-pattern and the drawbacks can be avoided via exporting a function or class.
It would make more sense to compare export default StateParser with exporting const methods.
See also:
All exports are static
ES6 modules are only evaluated once
Lost ES6 benefits