React.js - what is the good approach to show/hide loading image - javascript

I have a loading image in my page and a number of react components. In several components I need to implement the functionality of show/hide loading image.
So there are three options I can think of:
In each component, use a state variable and a loadingImage component to show hide the image. Like below code:
{this.state.showLoaidngImage ? <LoadingImage/> : null}
I can choose only to have this component at top-level component and let sub-components to call the parent display loading image method.
I can also use pure jquery here in each component and directly use the id to show/hide
The first approach seem to duplicate the component tags in each component and I am thinking of whether it is a good approach or not.
The second one is a bit complicated to implement.
The third approach seems dirty to me.
So which one should I use in the react world?

You should be going with the second approach because in that case you will not have to rewrite your loadingImage component again and according to the react good practices we should create components for everything, and use them wherever possible.

I think I would favor having your LoadingImage inside a component itself that handles hiding and showing via a prop. Something like this:
import React from 'react';
import PropTypes from 'prop-types';
import LoadingImage from 'where/this/exists';
const Loader = ({
show
}) => {
return (
{ show && <LoadingImage /> }
);
};
Loader.propTypes = {
show : PropTypes.bool.isRequired
};
export default Loader;
Then in your template:
<Loader show={ this.state.showLoader } />

(this result might be combined with #awildeep's response)
Assuming that you have React components that fetches to APIs, and those componends needs a "Loading image" separately, the first thing that comes into my mind is using redux and redux-promise-middleware.
Why?
You could have a global state, say for example
API_1: {
isFullfilled: false,
isRejected: false,
...
},
API_2: {
isFullfilled: false,
isRejected: false,
...
}
So, for instance, let's say that you have two React components that connects with those APIs. You will have two states!
{!this.state.API_1.isFullfilled && !this.state.API_1.isRejected : <LoadingImage /> : null }
Yes, this is too much code, but there's a way to simplyfy it, in mapStateToProps:
const mapStateToProps = state => {
const { API_1, API_2 } = state
return {
isFullfilled_API_1: API_1.isFullfilled,
isRejected_API_1: API_1.isRejected,
isFullfilled_API_2: API_2.isFullfilled,
isRejected_API_2: API_2.isRejected,
}
}
// Let's get those variables!
const { isFullfilled_API_1, isRejected_API_1 } = this.props
{ !isFullfilled_API_1 && !isRejected_API_1 ? <LoadingPage> : null}
You can track status for each component without a headache
You will accomplish your goal!
Hope it helps, and let me know if you have any concern!

Related

How to render ONE of multiple components conditionally that works well with React's change detector?

In my CRUD app, I have implemented several reuseable components like a "generic" DialogComponent and several non-reusable components. I have come across many scenarios where I need to (on the same page) either:
a) render one of multiple different non-reusable components conditionally like so:
return(
<>
{ condition111 && <Component_A>}
{ condition222 && <Component_B>}
</>
)
or b) pass different props to the same component conditionally. DialogComponent contains a form which renders different fields based on whether it is an ADD or EDIT dialog (depending on the props passed in):
return(<>
{
openAddDialog &&
<DialogComponent
rowAction={Utils.RowActionsEnum.Add}
setOpenDialog={setOpenAddDialog} />
}
{
openEditDialog &&
<DialogComponent
rowAction={Utils.RowActionsEnum.Edit}
setOpenDialog={setOpenEditDialog} />
}
</>)
^ This works fine, but idk if it is best practice to do it this way.
I was thinking maybe I could render a function that returns a component conditionally like below. QUESTION 1: Is this a good/bad idea in terms of React rendering?
export const GridComponent = (props) => {
...
const [gridName, setgridName] = useState(null);
useEffect(() => {
setGridName(props.gridName);
}, []);
const renderGrid = () => {
switch (gridName) {
case GridNameEnum.Student:
return <StudentGridComponent />;
case GridNameEnum.Employee:
return <EmployeeGridComponent />;
default:
return <h1>Grid rendering error.</h1>;
}
};
return(<>
{ renderGrid() }
</>)
}
QUESTION 2: What is the best way to handle this conditional rendering of a) one of multiple different components and b) same component rendered conditionally with different props? (Note: these are "child components" to be rendered on the same page)
You're asking two questions in one here and for opinions which is generally frowned upon but for the sake of trying to provide some guidance let's approach this in a functional way.
QUESTION 1: Is this a good/bad idea in terms of React rendering?:
It's fine because you only do one OR the other, never both but I'd still use a ternary if I were writing this myself to make it very clear that only one of these situations can ever occur:
enum DialogOptions {
Add,
Edit,
Delete
}
interface MyComponentProps {
DialogOption: DialogOptions
}
const MyComponent = ({ DialogOption }: MyComponentProps) => {
return DialogOption === DialogOptions.Add ? 'Add' : DialogOption === DialogOptions.Edit ? 'Edit' : DialogOption === DialogOptions.Delete ? 'Delete' : null
}
QUESTION 2: What is the best way to handle this conditional rendering of a) one of multiple different components and b) same component rendered conditionally with different props?
There are many ways you could do this and people will have different opinions. In the limited situation you've described your grid component obfuscates what is happening and means I have to dig in the code which is not helpful. It would be cleaner to:
Use a generic grid component which can be applied in multiple places (if this is possible, otherwise ignore this).
Create your StudentGridComponent and EmployeeGridComponent components which implement the generic grid component, or their own unique grid component if nothing can be shared.
Call the appropriate grid directly where it is required (whether this is a page or another component) using the ternary suggestion above (but put this inside your return and conditionally render the appropriate component or return some sort of empty message)
In terms of the way you've built your grid component I don't see the point of this. At the time where you're rendering your grid you should already be conditionally rendering either of the grids because you know you have that data, or you don't. There's no need for the complex state logic you've introduced within the grid component itself.

How to use the key attribute do in an img tag?

I have this code to make an array of images to display on the screen. However, I don't know what the key attribute in the images array means. Ideally I want to change the src of the image whenever one of the images is clicked. If I add in an id or className property to the image, and look it up using document.getElementById i get this warning: Warning: Prop `%s` did not match. Server: %s Client: %s%s when I rendered the page. I am using react and razzle for this project. Can someone tell me how to accomplish this?
var shuffle = require("shuffle-array"),
animals = [
"frog0",
"frog1",
// ...
"seal1",
"armadillo0",
"armadillo1"
];
function whatami(img) {
alert(img);
}
var images = shuffle(animals).map(image => {
return (
<img
onClick={() => {
whatami(image);
}}
key={image}
src={"/animalgameback.jpg"}
/>
);
});
const App = () => (
<div>
<h3>My razzle app</h3>
<div>{images}</div>
</div>
);
export default App;
There quite a few things wrong with your approaches here. I would highly suggest reading through the official React documentation on how to write Javascript in ReactJS.
Let's cover some basics. Firstly, you really should not ever be using document.getElementById in React (unless the situation is dire and you are trying to hack apart a third party library). For the most part, you use the prop ref to reference React Nodes that are mounted in the DOM. But, just some advice for those learning, have your fun with using references so that you know how to use them and what they do. But. I would suggest that if you "need" a reference or "need" to directly talk to a React component at run-time, you might be doing something wrong.
Now, since you are attempting to "change" something based on user events or interactions, this is a perfect use-case for state management. React comes with the ability for each component to self-encapsulate a stateful object and use these states to "trigger" or re-render things in components, due to this update or change.
What is a key? It is a unique identifier that you can use on each rendered JSX component that shows the virtual DOM and the real DOM, that this component is intended to be re-rendered as is rather than unmounted, changed and re-mounted. A key allows React to keep track of which components were intended versus just respawned or mounted. You always write a key of a JSX element as a unique id. If you made 2 id's the same (try it out and see :) ) you would notice that they render as 1 on the screen and one replaces the other.
Heres how I would write this:
I have made a single image as a "viewer" to show which image was clicked, along with a click event handler attached to the image to change the state. The render function detects the image source change and re-renders the component. Therefore, the new source is received and used and rendered.
The Code
import React, { Component } from 'react';
const ANIMAL_DATA = [
'frog0','frog1','sheep0','sheep1','snail0','snail1','mouse0','mouse1','bat0','bat1','walrus0',
'walrus1','giraffe0','giraffe1','zebra0','zebra1','dog0','dog1','octopus0','octopus1','hippo0',
'hippo1','camel0','camel1','pig0','pig1','rhino0','rhino1','rooster0','rooster1','panda0','panda1',
'turtle0','turtle1','raccoon0','raccoon1','polarbear0','polarbear1','lion0','lion1','bison0',
'bison1','orca0','orca1','snake0','snake1','shark0','shark1','toucan0','toucan1','butterfly0',
'butterfly1','anteater0','anteater1','seal0','seal1','armadillo0','armadillo1'
]
class App extends Component {
constructor(props) {
super(props);
this.state = {
imageSource: 'animalgameback',
};
}
render() {
const { imageSource } = this.state;
return (
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
<img style={{ width: 143, height: 'auto' }} source={require(`/${imageSource}.jpg`)} />
{ this.renderAnimalImages() }
</div>
);
}
renderAnimalImages() {
let images = [];
ANIMAL_DATA.forEach((animal, animalIndex) => {
// Be careful when assigning "onclick" methods to images,
// you are better off sticking with W3C rules on this. Use elements
// meant for "clicking" or "being clicked", i.e. <a>, <button>, etc
images.push(
<img
src={`/${animal}.jpg`}
key={`anima_image_${animalIndex}`}
onClick={this.__handleImageClick(animal)} />
);
});
return images;
}
__handleImageClick = animal => event => {
this.setState({ imageSource: animal });
};
}
export default App;
The key attribute serves as an identity declaration. It helps rendering engine to decide which elements should be re-rendered.
It's well explained in the documentation.

How to conditionally return a component in React/Native?

I've used a tool to create React-native components from .svg files. It works well and I can load them using that way.
However, how do I conditionally load them?
I've imported some company logos as such:
import Tesla from '../../static/brandlogos/svg/Tesla'
import Amazon from '../../static/brandlogos/svg/Amazon'
import Google from '../../static/brandlogos/svg/Google'
import Facebook from '../../static/brandlogos/svg/Facebook'
import Apple from '../../static/brandlogos/svg/Apple'
Indeed, if I invoke the component as such, it works:
<Amazon />
However, I wish to(of course) conditionally load a component depending on the props this component receives. So, I create a function:
renderLogo (brandName) {
const Logos = {
Amazon,
Facebook,
Tesla,
Google,
Apple
};
if (Logos[brandName]) {
return <Amazon /> // This works!
}
if (Logos[brandName]) {
return Logos[brandName] // This doesn't!
}
if (Logos[brandName]) {
return Logos.Amazon // This also doesn't!
}
}
However, I simply cannot figure out how to create either a map or array to loop through, and render the specific component. If I straight up return the component, of course it works.
But how do I save each "Logo" in an array or map, and conditionally load + return this logo only?
I could, of course, hard code everything but that would be bad.
Simply do like this
if (Logos[brandName]) {
// Keep in mind the first letter should be capital (i.e. "C" in this case)
let Comp = Logos[brandName]
return <Comp />
}
I think, this post on Dynamic Component Names with JSX answers your question nicely:
components = {
foo: FooComponent,
bar: BarComponent
};
render() {
const TagName = this.components[this.props.tag || 'foo'];
return <TagName />
}
In this example you have your tag from the prop - the most typical case for many components.

How to render results of search in another component in React?

I am a beginner in React and using Webpack to build into a bundle.js and display.
My need is to provide some search forms and accordingly display result below search form. So, for modularizing it, I have create a parent component containing both search and result view components.
Now that I have designed a form and written form onSubmit event handler, how should i proceed to render API results (dummy json for now) in the result component. I am attaching a brief pic of my intention for your reference.
Here is my solution based on my comments above: https://codesandbox.io/s/q85oq0w10q
Create an HOC that will hold the state of your app, then your two children are merely used for rendering purpose and can be made pure functions
import React from 'react';
import { render } from 'react-dom';
const Result = ({results}) => {
return results.map((r, i) => <div key={i}>{r}</div>);
}
const Search = (props) => {
const {
searchQuery,
onChange,
search
} = props;
return <div>
<input
type="text"
value={searchQuery}
onChange={onChange}
/>
<button onClick={search}>Search</button>
</div>;
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
searchQuery: '',
results: []
}
this.onSearchQueryChange = this.onSearchQueryChange.bind(this);
this.onSearch = this.onSearch.bind(this);
}
onSearchQueryChange(e) {
this.setState({searchQuery: e.target.value});
}
onSearch() {
// Simulate AJAX call
setTimeout(() => {
this.setState({results: [0, 1, 2, 3, 4]});
}, 1000)
}
render() {
const {results, searchQuery} = this.state;
return <div>
<Search
searchQuery={searchQuery}
onChange={this.onSearchQueryChange}
search={this.onSearch}
/>
<Result results={results} />
</div>;
}
}
I believe this is what you are looking for. Worked example fiddle
So the idea is to keep your result in Container component and pass it down to Result component. Also Container component should pass a callback function to your Search component and it will be triggered with a API result from the Search component.
Also you may want to take a look at Redux. This is a library for managing your app state. With Redux it can be achieved in more easiest way.
Hope it will help you.
In my opinion if you are new in React. You should learn first using React. Because I see that a lot of people use Redux(or any other app state handler) as a storage for any data.
Your case is actually very good example to learn two of the basic ideas: if children need similar thing, parents should handle it and params go down and callbacks go up.
So all your logic has to be in Container Component, make callback of http request function, with update of state(setState) after resolving response and send to Search Component. onSubmit call that callback, and send data to Result Component.
So you no need of additional library(maybe for http request).
1 Class component(Container Component). 2 Probably stateless functional components(Search Component & Result Component).

Is this a good React practice?

I have recently started playing around with React. In order to animate my components (using CSS animation), I have put this block of code in my index.js:
// some code here
window.onload = () => {
let myComponents = document.getElementsByClassName('componentThatHaveToBeAnimated')
for (let c of myComponents) {
// add dinamically the CSS class containing the animation
}
}
//some code here
I do this in order to be shure that all the animations will start only when the page is properly loaded.
My question is: is this correct? And, if it is not, there is a better way to achieve the same effect?
React is great, but when having used Javascript (as it seems you have), it can be a bit tricky to understand and difficult to adjust (from experience). There is a great youtube tutorial on React by learncodeacademy, which really helps you understand react. You may also want to look at create react app for an easy way to set up a React project.
Now to your question :) This is not a good practice. React has its own "window.onload" called componentDidMount
Also you should not be using getElementBy unless absolutely necessary.
The beautiful thing about react is using states.
You css value should be a state.
An example of this would be:
import React, { Component } from 'react'
import MyComponent from './MyComponent'
class Animation extends Component {
constructor() {
super() //this always has to be called first in a constructor
this.state = {
animationCSS: '',
}
this.changeAnimationCSS = this.changeAnimationCSS.bind(this)
}
componentDidMount() {
const getAnimationCSSFromDB = db.get(animationCSS) //This obviously does not work, but an example
this.setState({
animationCSS: getAnimationCSSFromDB
})
}
changeAnimationCSS() {
this.setState({
animationCSS: //Whatever new css you may want
})
}
render() {
return (
<MyComponent propertyForStylingAnimation={this.state.animationCSS} />
<button onClick={this.changeAnimationCSS} label="Button" />
)
}
}
export default Animation
MyComponent might in this case look something like this
import React from 'react'
const MyComponent = props =>
<div style={{ animate: props.propertyForStylingAnimation }}> // This does not work for animating since animate is not a css property.
// Stuff
</div>
export default MyComponent
Understanding props can be a bit tricky, but if you follow the youtube tutorial by learncodeacademy, you will get it.
Notice that the second bit of code is much shorter.
This is because it is stateless. What this means is simply that there are no states.
This means I do not need to define the class that extends component, I can just use a constant. I also do not need to define render or return, since there is only one element (the div) that is being returned, no brackets are needed. This is not something you need to worry about initially when learning React but it is good practice.

Categories