What is state in React? - reactjs

I know that state allows us to create components that are dynamic and interactive but I want to deep in state.
Can someone help me to understand state in React using a real life example?

import React from 'react';
class App extends React.Component {
state = {
count: 0
};
render() {
return (
<div>
<h1>Hello world</h1>
<h2>Count: {this.state.count}</h2>
<button
onClick={() => this.setState(state => ({ count: state.count + 1 }))}
>
+
</button>
<button
onClick={() => this.setState(state => ({ count: state.count - 1 }))}
>
-
</button>
</div>
);
}
}
export default App;
In the above code, it has a state object with property/state: count.
State can simply be understand as a value at that point of time of the particular component/app. In the above example, when the app is first running, the app is with state count === 0
As we can see there are two buttons + and - that update the value using this.setState, it simply update the "state" of count for the app, and the app will re-render, whenever the state change

For example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
state = {
show: false,
}
showTextToggle = () => {
this.setState({ show: !this.state.show });
}
render() {
const { show } = this.state;
return (
<div>
<h3>Some title</h3>
{show ? <div>Description</div> : undefined}
<button onClick={this.showTextToggle}>Read more</button>
</div>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
P.S. CodeSandBox

State in real life example:
Before someone upvoted your question, you can imagine your question or think it as question component had vote state = 0 and after that it became 1 and so on. So interactivity with the application changed something in the application. That changed something/ value can be called state.
State in application/ component can change due to interactivity(event) or during time.
As time you can imagine this Post or Post Component before 30 minutes/ some time ago had no answer i.e answer state = 0. And now it has some (3) answers. So answer state = 0 changed to answer state = 3.
State is just a value that a component/app is in at particular time.
Just imagine the specific point of time when you posted this question and now see the changes in this post. This changes can be thought as change in the state of the component/ app.

The state is an instance of React Component Class can be defined as an object of a set of observable properties that control the behaviour of the component. In other words, the State of a component is an object that holds some information that may change over the lifetime of the component. For example, let us think of the clock that we created in this article, we were calling the render() method every second explicitly, but React provides a better way to achieve the same result and that is by using State, storing the value of time as a member of the component’s state. We will look into this more elaborately later in the article.

State allows you to create components that are dynamic and interactive.
It holds information about the current state of the app. You can keep your variables and your data inside the local state of the React app by doing,
class App extends Component{
state = {
didUserLogin: false
}
}
Then, you can directly access the state using,
console.log(this.state.didUserLogin);
or update it with,
this.setState({didUserLogin: true});
As you keep manipulating the data inside the state, the components that use the state will be updated with the information you provided for the state.
More information,
https://thinkster.io/tutorials/understanding-react-state
https://reactjs.org/docs/state-and-lifecycle.html

class App extends Component {
constructor(props){
super(props);
this.state = {products: []};
}
render() {
console.log(this.state);
return (
<div className="container">
</div>
);
}
}
In the latest react, we now can define state as a plain JavaScript object and the render method gets it correctly. Here is an example of state as a plain object outside constructor:
In the latest react, we now can define state as a plain JavaScript object and the render method gets it correctly. Here is an example of state as a plain object outside constructor:
class App extends Component {
constructor(props){
super(props);
}
state = {products: []}
render() {
console.log(this.state);
return (
<div className="container">
</div>
);
}
}
More Details
https://www.codegreet.com/how-to-use-state-in-reactjs/

Related

How to render component depends role

so I have a specific code.
The problem is it's not works in moments - when it's should.
I need refresh page to works.
If user from LocalStorage is null it's should render
If user from LocalStorage exist it's shouldn't render
It's works, but how can I improve it to works after login (not after refreshing page) ?
Should I use other react lifecycle method?
class Navbar extends React.Component {
constructor(props){
super(props)
this.state ={
user: null
}
}
componentDidMount(){
const user = JSON.parse(localStorage.getItem('user'));
this.setState({
user: user
},
console.log('test'+ this.state.user)
)
}
render(){
return(
<div>
{ !this.state.user ?
<div className ="navbar">
<Logo/>
<Menu/>
<PanelOptions/>
</div>
: null}
</div>
);
}
}
Looking at the component it seems that it can be a functional component.
And the user can be sent as a prop from parent component which is rendering the NavBar component.
export default NavBar = (props) => {
if(!props.user)
{
return (
<div className ="navbar">
<Logo/>
<Menu/>
<PanelOptions/>
</div>
)
}
else
{
return null
}
}
Should I use other react lifecycle method?
No, it won't help. Local storage change is not observed, can't be a reason of rerendering.
What is the reason of storing user data in local storage? Sharing data between components shouldn't be the [primary] one.
Components are rerendered on props or state changes. You can pass some value (f.e. isLogged or simply user) from parent state (where probably the login process is handled). If login is processed in sibling child that you need lifting state up - one of basic react techniques.

React-Redux Dispatch design

Overview
We have a page with a header (Blue color) and content section (Green color) that can be seen in image below. The requirement is when a user selects a year in header, then the content page will show data as per the selected year.
What is happening right now Technically
When user selects a year in header, we dispatch the selected value and the active container's mapStateToProps function is triggered and the selected year is passed to the component.
class Page1Content extends Component {
}
function mapStateToProps(state) {
return { selectedYear : state.userSelectedValue };
}
export default connect(mapStateToProps, null)(Page1Content);
Question 1
How will data on Page1Content will refresh? Few approaches:
In ComponentDidUpdate react life cycle method of the Page1Content API to fetch data can be called. However have seen opinions where we should avoid React hooks and life cycle methods with Redux.
In mapStateToProps function API can be called.
Can any one suggest what is the better place to call the API?
Question 2
Data on Page1Content will be used only by this page. This data will not be used by any other component and hence need not be shared by any other Component. Now question 2 is
In case we decide to use ComponentDidUpdate should we again dispatch the API call using Thunk or any other library and then catch the response in mapStatesToProps again?
Or we should make the API call and resolve it in the component itself as a promise. Then the response will be set in State and respective Template will be refreshed.
ComponentDidUpdate is a lifecycle method not a hook. Hooks is functionality that allows functional components to have class based functionality such as state.
You are using a class based component in your example so you are not using hooks.
https://reactjs.org/docs/hooks-intro.html
Yes Redux shouldnt be used with hooks since context is a better option.
You can lift state up so to speak and update the local state in the parent component getting rid of redux completely.
Just pass down the setState function and the state itself to the appropriate children.
class App extends Component {
constructor(props) {
super(props);
this.state = {
some_prop: false
}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({some_prop: true})
console.log('Click happened');
}
render() {
return (
<Header onClick={this.handleClick } />
<Page1Component props={this.state.some_prop} />
}
}
Edit:
Question 1
How will data on Page1Content will refresh?
best option is with a ternary expression in your render method, there is no need to check if the state updated. In react if the state is changed your component will automatically re render.
render() {
return (
<div>
{this.props.selectedYear
? <p> {this.props.selectedYear}</p>
: null
}
</div>
}
}
Question 2
Data on Page1Content will be used only by this page. This data will not be used by any other component and hence need not be shared by any other Component. Now question 2 is
If I understand this correctly you will need to use an action creators, redux thunk is overkill here.
class Header extends Component {
constructor(props) {
super(props);
}
handleClick() {
this.props.dispatchActionCreator({some_value})
console.log('Click happened');
}
render() {
return (
<button onClick={(some_value) => this.handleClick(some_value)}>Click </button>
}
}
function mapDispatchToProps(state) {
return {
dispatchActioNCreator: (some_value) => dispatch(ACTIONS.action_creator(some_value) };
}
This will save your value from your header to the global redux state and then you can just access with mapStateToProps in your Page1Component.

How to change state of component from anywhere without Redux?

Is this bad practices or not ?
export state change function from component
import it from other file.
call the function to change state?
In this way we can change some component state from anywhere.
For example...
We want to change the Model.js state from anywhere.
Modal.js
import React from 'react';
export let toggleModal;
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
};
toggleModal = this.toggleModal;
}
toggleModal = () => {
this.setState({ open: !this.state.open });
};
render() {
const { open } = this.state;
return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
}
}
App.js(Some Top Level component)
import React from 'react';
import Modal from './Modal';
export default () => (
<>
...
<Modal />
...
</>
);
Somewhere.js
import React from 'react';
import {toggleModal} from './Modal';
export default () => (
<>
<h1>Hello!</h1>
<button onClick={() => toggleModal()}>open Modal!</button>
</>
);
  
But there is no reference in React Official docs, so is this bad practices ?
What React Docs recommends...
Just passing function props to change parent state from parent to children
Use context
Redux or Mobx
But, these are too complex for me.
Example code here
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview
Everything seems pretty much overwhelming and difficult at the beginning. But as we get out hands on them, it's give us more confidence to dig into.
I would recommend to use redux that's how we tackled props drilling problem. You can dispatch a action and connect reducer to corresponding component which upon updating state will re render. This is what I recommend to most of the people to learn the tale of redux with a real life example:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
Apart from this you can take Dan Abramov, author of the library, free redux course on egghead.io:
Getting Started with Redux
The problem you run into, almost immediately like your code example does is this:
It will not work: your toggleModal() method expects a this to refer to an actual component instance. When your onClick() handler fires you invoke toggleModal() as a plain function. The this context will be wrong, and so at best (in your example) you will get an error because you try to invoke something undefined, at worst (in general) you end up invoking the wrong method.
When you think about it, for any non-trivial React component you will have a hard time obtaining a reference to the actual instance that is currently being used: you have to make sure that you are not forgetting to invoke the method on the right component instance and also you have to consider that instances may be created/destroyed 'at will' for whatever reason. For example: what if your component is rendered indirectly as part of some other component's render() method? Multiple layers of indirection like that make it even harder.
Now, you could fix all that by abusing ref with abandon but you will find that now you have to keep track of which ref refers to what particular instance, if you happen to have multiple of the components to consider in one render tree...
Whenever you think one component needs to handle the state of its siblings, the solution is usually to lift the state one level up.
export default class Modal extends React.Component {
render() {
const { isOpen } = this.props;
return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
}
}
export default class Home {
this.state = {
isOpen: false,
};
toggleModal = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
const { isOpen } = this.state;
return (
<>
<h1>Hello {name}!</h1>
<button onClick={() => this.toggleModal()}>open Modal!</button>
<Modal isOpen={isOpen}/>
<p>Start editing and see your changes reflected here immediately!</p>
</>
)
}
}
This way the Home handle the state and your problem is solved.
This can get annoying if the state needs to be "drilled down" to children, that's a problem than redux or react-context can solve.
Here <Modal /> is the child component. So to call a function in a child component you can simply use Ref.
You can refer this page to get more info about Ref.
You can assign a class variable as a ref to this child and use this class variable as an object to call its function.
I found if in special case, my way is okay.
Special case means something like customAlert component.
It is okay only one instance of customAlert component mounted at a time in App.
To achieve this...
1.Use ref to access and change DOM
2.attach state changing function or component to window and call window.function
3.my case: export state changing function and import it from other file.
And here is how to do with react Context
https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview
I think Redux is overkill if the main thing you are interested in is to make some states-like data available and updatable throughout your App without props drilling.
For that purpose, a much simpler approach (maybe not available at the time the question was posted?) is to use react context: https://frontend.turing.edu/lessons/module-3/advanced-react-hooks.html
"context - an API given to us by React, allowing for the passing of
information to child components without the use of props
[...]
useContext - a react hook, allowing functional components to take
advantage of the context API"

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.

How to refresh props with React/Redux when user enters a container

I have CompetitionSection which repeats all the competitions from database. When user clicks on one, it redirects him to a Competition Page, loads for a second and renders the page with all the details in it. So far, so good.
But when users goes back to the Competition Section and then click on the second competition, it instantly loads up the previous competition, 0 loading time.
From my point of view, what is failing is that the props of the component are not updating when I render the component (from the second time). Is not a router problem, which was my first instinct because I'm seeing the route.params changing acordingly, but the actions I dispatch to change the props are not dispatching. Here's a bit of code of said component.
class CompetitionPage extends React.Component {
componentWillMount() {
let id = getIdByName(this.props.params.shortname)
this.props.dispatch(getCompAction(id));
this.props.dispatch(getCompMatches(id));
this.props.dispatch(getCompParticipants(id));
this.props.dispatch(getCompBracket(id));
}
render() {
let { comp, compMatches, compBracket, compParticipants } = this.props
...
I tried every lifecycle method I know. component Will/Did Mount, component Will/Did update and I even set shouldUpdate to true and didn't do the trick. As I understand, the problem will be solved with a lifecycle method to dispatch the actions everytime an user enters Competition Page and not just for the first time. I'm running out of options here, so any help will be appreciated.
NOTE: I'm a newbie at React/Redux so I KNOW there are a couple of things there are anti-pattern/poorly done.
UPDATE: Added CompetitionsSection
class CompetitionsSection extends React.Component {
render() {
const {competitions} = this.props;
return (
...
{ Object.keys(competitions).map(function(comp, i) {
return (
<div key={i} className={competitions[comp].status ===
undefined? 'hide-it':'col-xs-12 col-md-6'}>
...
<Link to={"/competitions/"+competitions[comp].shortName}>
<RaisedButton label="Ver Torneo" primary={true} />
</Link>
...
It helps to better understand the lifecycle hooks. Mounting a component is when it is placed on the DOM. That can only happen once until it is removed from the DOM. An UPDATE occurs when new props are passed or setState is called. There are a few methods to troubleshoot when updates are not happening when you think they should:
Ensure that you are changing state in componentDidMount or componentDidUpdate. You cannot trigger an update in componentWillMount.
Make sure that the new props or state are completely new objects. If you are passing an object down in props and you are just mutating the object, it will not trigger an update. For instance, this would not trigger a update:
class CompetitionPage extends React.Component {
constructor(props) {
super(props)
this.state = {
competitions: [ compA, compB ]
}
}
triggerUpdate() {
this.setState({
competitions: competitions.push(compC)
})
}
componentDidMount() {
triggerUpdate()
}
render() {
return(
<div>
Hello
</div>
)
}
This is due to the fact that a new competition is being appended to the array in state. The correct way is to completly create a new state object and change what needs to be changed:
const newCompetitions = this.state.competitions.concat(compC)
this.setState(Object.assign({}, this.state, { competitions: newCompetitions }))
Use ComponentWillRecieveProps on an update to compare previous and current prop values. You can setState here if clean up needs to be done:
Read more about this method in the React documentation:
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops

Resources