ReactJs: Intial Component Rendering doesn't seems to work - reactjs

I'm working on a project and came across this issue that first time when component is rendered, it doesn't shows anything on the screen. Then componentDidMount is invoked and after that something is visible on the screen.
My App Component
class App extends React.Component {
state={loading: true};
componentDidMount(){
alert("Inside did mount");
this.setState({loading: false});
}
render() {
alert(this.state.loading);
if (this.state.loading) {
return <div>Loading...</div>;
}
return(
<div>After ComponentDid Mount !</div>
)
}
}
In above code, initially Loading... should be visible on the screen for the first time. But this isn't happening.
Am I doing some kind of mistake here ?
Is there any way to show Loading... on the screen first and after that componentDidMount will run ?

your state for a class component needs to be inside a constructor.
constructor(props) {
super(props)
this.state = {your state}
}
Now that will allow you reference it as the component using (this)
It’s currently a normal variable and isn’t used as this.state but just state but that means changes to this variable may not reflect to changes to the pages. Further reading on this:
https://reactjs.org/docs/hooks-state.html
Also you may want to begin using functional components the way you wrote your render()
In my experience It’s preferable to have a single return in render and then from that return call upon functions and variables to render the page differently

It mounts the component fast so you can't see the loading text. You can use the setTimeout function to mimic remote server requests and latency.
import React from "react";
class App extends React.Component {
state = { loading: true };
componentDidMount() {
setTimeout(() => {
this.setState({ loading: false });
}, 5000);
}
render() {
if (this.state.loading) {
return <div>Loading...</div>;
}
return <div>After ComponentDid Mount !</div>;
}
}
export default App;

Related

will puting function inside render method slow my app

i am learning react, i am django developer and i am getting data from api and is working fine, just for a fun i wanted to update data without clicking reload, so what i did is put fetch function inside render which is looping , and it is giving real time feel, but i want to know that will doing this like this slow my app like in vannila js, since it is rendering again and again, but since react uses virtual dom i have soft side on this technique
import React from 'react';
class FetchRandomUser extends React.Component {
constructor(){
super();
this.state = {
data: [],
};
}
fetchdata(){
fetch('http://127.0.0.1:8000/api')
.then(response=>response.json())
.then((data)=>{
this.setState({
data:data,
});
console.log(data);
});
}
componentDidMount(){
this.fetchdata();
}
render() {
this.fetchdata();
const dat = this.state.data;
const rows = dat.map((emp)=>
<div>
<h1>{emp.id}</h1>
<h1>{emp.title}</h1>
<h1>{emp.body}</h1>
</div>
);
return (
<div>
{rows}
</div>
)
}
}
export default FetchRandomUser;
You shouldn't use fetch inside render method. Because in your code when this.fetchData() is run, as you can see you are setting the state in that method using setState(), and setState itself calls render method so your code will result in an infinite loop.
Also You shouldn't use fetch inside render method because every time render is called your fetchData() will run which will slow your program as it takes time to fetch data from a server.

Triggering animation via setState not working

I am calling a function when I hit a waypoint in my page. The function logs the state after calling setState, which shows that the state has been updated to {visible: true} however, in React Dev Tools, it shows that the state is still false. Because the state is still false, the Animated component isn't visible. If I change visible to true using React Dev Tools, the Animated component becomes visible.
I think my problem is because my setState isn't updating the component state outside of the function call, this would explain why logging the component's state shows as updated in console but not triggering a rerender nor making the Animated component's isVisible property set to true via the state attribute.
This is the component I am working on
import React, { Component } from 'react'
import { Waypoint } from 'react-waypoint'
import { Animated } from 'react-animated-css'
export default class About extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
};
this.OnEnter = this.onEnter.bind(this);
}
onEnter({ currentPosition }){
this.setState({
visible: true
});
console.log(this.state);
};
render() {
return (
<Waypoint onEnter={this.onEnter}></Waypoint>
<Animated animationIn="fadeInUp" isVisible={this.state.visible}>
<h2 className="mb-4">About Me</h2>
<p>A small river named Duden flows by their place and supplies it with the necessary nutrients.</p>
</Animated>
);
}
}
Posting my comment as the answer.
There is a typo error.
Please update the line this.OnEnter = this.onEnter.bind(this); to this.onEnter = this.onEnter.bind(this);.

React / Redux Components not re-rendering on state change

I think this question has been answer several time but I can't find my specific case.
https://codesandbox.io/s/jjy9l3003
So basically I have an App component that trigger an action that change a state call "isSmall" to true if the screen is resized and less than 500px (and false if it is higher)
class App extends React.Component {
...
resizeHandeler(e) {
const { window, dispatch } = this.props;
if (window.innerWidth < 500 && !this.state.isSmall) {
dispatch(isSmallAction(true));
this.setState({ isSmall: true });
} else if (window.innerWidth >= 500 && this.state.isSmall) {
dispatch(isSmallAction(false));
console.log(isSmallAction(false));
this.setState({ isSmall: false })
}
};
componentDidMount() {
const { window } = this.props;
window.addEventListener('resize', this.resizeHandeler.bind(this));
}
...
I have an other component called HeaderContainer who is a child of App and connected to the Store and the state "isSmall", I want this component to rerender when the "isSmall" change state... but it is not
class Header extends React.Component {
constructor(props) {
super(props);
this.isSmall = props.isSmall;
this.isHome = props.isHome;
}
...
render() {
return (
<div>
{
this.isSmall
?
(<div>Is small</div>)
:
(<div>is BIG</div>)
}
</div>
);
}
...
even if I can see through the console that redux is actually updating the store the Header component is not re-rendering.
Can someone point out what I am missing ?
Am I misunderstanding the "connect()" redux-react function ?
Looking at your code on the link you posted your component is connected to the redux store via connect
const mapStateToProps = (state, ownProps) => {
return {
isHome: ownProps.isHome,
isSmall: state.get('isSmall')
}
}
export const HeaderContainer = connect(mapStateToProps)(Header);
That means that the props you are accessing in your mapStateToProps function (isHome and isSmall) are taken from the redux store and passed as props into your components.
To have React re-render your component you have to use 'this.props' inside the render function (as render is called every time a prop change):
render() {
return (
<div>
{
this.props.isSmall
?
(<div>Is small</div>)
:
(<div>is BIG</div>)
}
</div>
);
}
You are doing it well in the constructor but the constructor is only called once before the component is mounted. You should have a look at react lifecycle methods: https://reactjs.org/docs/react-component.html#constructor
You could remove entirely the constructor in your Header.js file.
You should also avoid using public class properties (e.g. this.isSmall = props.isSmall; ) in react when possible and make use of the React local state when your component needs it: https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
A component is only mounted once and then only being updated by getting passed new props. You constructor is therefore only being called once before mount. That means that the instance properties you set there will never change during the lifetime of your mounted component. You have to directly Access this.props in your render() function to make updating work. You can remove the constructor as he doesn't do anything useful in this case.

Render methods issue - React js

Here I'm trying to get value from DefaultOpts.jsx and update the values to setState in Filters.jsx. But I'm getting error as below :
setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.
Filters.jsx
import React from 'react';
import DefaultOpts from 'DefaultOpts.jsx';
export default class Filters extends React.Component {
constructor(props) {
super(props);
this.state = {
vOptions : []
}
this.handleOptions = this.handleOptions.bind(this)
}
handleOptions(params) {
console.log(params)
this.setState({
vOptions : params
});
}
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return (
<div>
<DefaultOpts handleOptions={this.handleOptions.bind(this)} />
</div>
)
}
}
DefaultOpts.jsx
import React from 'react';
class DefaultOpts extends React.Component{
constructor(props) {
super(props);
}
componentDidMount() {
}
componentDidUpdate() {
}
render() {
var optArray = "";
$.ajax({
type: "get",
url: "url-path",
success: function(data) {
optArray = data;
}
});
return (
<div>
{this.props.handleOptions(optArray)}
</div>
)
}
}
export default DefaultOpts;
I got some answers in stackoverflow but I'm not able to get what's issue in my code. Please suggest me here what's wrong in my code..
You can't call this.props.handleOptions inside the render because it will trigger setState of the parent component - and you are still inside the rendering process. That's why it complains.
Try to execute this function inside the componentDidMount (together with your ajax call)
There are several problems with your code:
1) First and main one that results in the mentioned error is the fact that by calling handleOptions in render you are calling setState that in turn starts react life cycle. This is a really bad practice and always should/can be avoided.
2) You have one more async call to $.ajax in render that does not directly result in updating state but still considered a bad practice.
To conclude - your render function must not result in any app logic being performed, its task is to render results that have already been prepared. Do all heavy/async work in componentDidMount/componentDidUpdate and you will be fine.
render will execute before didMount... so you are setting the state before it is mounted
anyway move the $.ajax call to didMount, you shouldn't be doing logic things in render()

Updating child props from parent state in ReactJS

I'm trying to understand how I can structure a ReactJS app with different "pages" or "views".
I have the following component as my base app and I'm using a currentState property in the React state to switch between which Components are active in the view.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {currentState: 'Loading', recipes: []};
this.appStates = {
'Loading': <Loading/>,
'Home': <RecipeList recipes={this.state.recipes}/>
}
}
dataLoaded(data) {
this.setState({
recipes: data,
currentState: 'Home'
});
}
componentDidMount() {
// AJAX Code that retrieves recipes from server and then calls dataLoaded
}
render() {
return this.appStates[this.state.currentState];
}
}
Which does the job, but the component never receives the updated recipes array when the dataLoaded callback is fired.
How can I cause the to update its props based on the updated state in the App?
Or am I approaching this whole thing the wrong way?
I think that your aproach isn't really react-like, and you have at least a couple of concepts that can be improved.
First of all, I would definitely use react-router to achieve any complex navigation between pages/Components in React.js. Implementing it yourself is more complicated and error-prone. react-router will allow you to assign Components to different routes easily.
Second, I think that you should almost never store things in the context this directly. Basically because it leads to errors like yours here: not realizing that appStates isn't changing at all. React's state is a great tool (which must sometimes be replaced/complemented with others like Redux) to store your application's state.
In the case of storing in the state what should be rendered in the Component, you should probably complement the react-router functionality with simple flags in the state initializated in the constructor that allow you to know what should you return in the render function.
Here is an example that shows how can you tell a component to change its view dynamically between loading and loaded by using just React's state. Of course, you could recreate a very similar behaviour making an AJAX call in componentDidMount and changing the state to stop loading when it's done instead of using a button.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {loading: true};
this.stopLoading = this.stopLoading.bind(this);
}
stopLoading() {
this.setState({
loading: false,
});
}
render() {
let view=<div><h1>loading</h1><button onClick={this.stopLoading}>FINISH</button></div>;
if(!this.state.loading){
view=<h1>loaded</h1>;
}
return <div>{view}</div>;
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<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>
<div id="container"></div>
Your constructor method is only executed when the component mounts, at which point recipes is empty, and passes that empty array to appStates. Essentially, appStates never changes.
What I would recommend doing is pushing all the component code in the constructor to inside the render function. The beauty of react is that you can completely re-render everything at very little cost. React will do the hard work of comparing the difference in DOMs and only re-render the minimal differences.
I agree with #Ezra Chang. I think the code could be adjusted making use of just the state and the javascript spread function to pass the App props to the child RecipeList:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {currentState: 'Loading', recipes: [],'Loading': <Loading/>,
'Home': <RecipeList recipes={this.state.recipes} {...this.props}/>};
}
//I assume you want to pass the props of this App component and the data from the back-end as props to RecipeList.
dataLoaded = (data) => {
this.setState({
recipes: data,
currentState: 'Home',
'Loading': <Loading/>,
'Home': <RecipeList recipes={data} {...this.props}/>
});
}
componentDidMount() {
// AJAX Code that retrieves recipes from server and then calls dataLoaded
}
render() {
return this.state[this.state.currentState];
}
}

Resources