Reset initial state in React + ES6 - javascript

I have a class, ElementBuilder below, and when the user saves the Element they've built, I want the state to reset to the values below.
I have some functions in this class that I haven't provided but that change the state of title, size, and color.
In ES 5, I would have a getInitialState function on my class and could call this.getInitialState() in a function.
This element lives in my app for the lifecycle of a logged in user and I want the default values to always be the same regardless of past usage.
How do I achieve this without writing a function that sets an object of default values (or maybe that's the answer)? thanks!
class ElementBuilder extends Component {
constructor(props) {
super(props);
this.state = {
title: 'Testing,
size: 100,
color: '#4d96ce',
};
}
resetBuilder() {
this.setState({ this.getInitialState() });
}
}

You may use a getter function:
class ElementBuilder extends Component {
constructor(props) {
super(props);
this.state = this.initialState;
}
get initialState() {
return {
title: 'Testing',
size: 100,
color: '#4d96ce',
};
}
resetBuilder() {
this.setState(this.initialState);
}
}
or just a variable:
constructor(props) {
super(props);
this.initialState = {
title: 'Testing',
size: 100,
color: '#4d96ce',
};
this.state = this.initialState;
}

Using the proposed class fields, you could do something like this:
class ElementBuilder extends Component {
static initialState = {
title: 'Testing',
size: 100,
color: '#4d96ce'
}
constructor(props) {
super(props)
this.state = ElementBuilder.initialState
}
resetBuilder() {
this.setState(ElementBuilder.initialState)
}
}

Since the initial state doesn't seem to depend on anything instance specific, just define the value outside the class:
const initialState = {...};
class ElementBuilder extends Component {
constructor(props) {
super(props);
this.state = initialState;
}
resetBuilder() {
this.setState(initialState);
}
}

Use an High Order Component to clear component state (rerender)
Exemple Element.jsx :
// Target ----- //
class Element extends Component {
constructor(props){
super(props)
const {
initState = {}
} = props
this.state = {initState}
}
render() {
return (
<div className="element-x">
{...}
</div>
)
}
}
// Target Manager ----- //
class ElementMgr extends Component {
constructor(props){
super(props)
const {
hash = 0
} = props
this.state = {
hash, // hash is a post.id
load: false
}
}
render() {
const {load} = this.state
if (load) {
return (<div className="element-x"/>)
} else {
return (<Element {...this.props}/>)
}
}
componentWillReceiveProps(nextProps) {
const {hash = 0} = nextProps
if (hash !== this.state.hash) {
this.setState({load:true})
setTimeout(() => this.setState({
hash,
load:false
}),0)
}
}
}
export default ElementMgr

Related

useState in class component

can anyone tell me how to transfer it to form acceptable in class component? Thanks
const [isAuth, setIsAuth] = useState(localStorage.getItem("isAuth"));
Something like the following
define the state in the constructor and initialize it with the value you use in the useState
create a setIsAuth method that sets the state to the new value passed
class YourComponent extends React.Component{
constructor(props){
super(props);
this.state = {
isAuth: localStorage.getItem("isAuth")
}
}
setIsAuth = (newValue) => {
this.setState({
isAuth: newValue
});
}
render() {
...
}
}

Getting a warning called Can't call setState on a component that is not yet mounted

This is my code
import React, { Component } from 'react';
class Rando extends Component {
constructor(props) {
super(props); // want to use props insode brackets if we want to use props inside the constructor
this.state = { num: 0, color: 'purple' };
this.makeTimer();
}
makeTimer() {
setInterval(() => {
let rand = Math.floor(Math.random() * this.props.maxNum);
this.setState({ num: rand });
}, 10);
}
render() {
console.log('changing');
return (
<div className=''>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default Rando;
I'm getting a warning that looks like this
index.js:1 Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the Rando component.
I'm a beginner, I have no idea what's causing this. please help me. Thanks in advance
Your timer function gets executed even before the component gets mounted. Try putting the code inside componentDidMount hook. Also don't forget to clear the interval id inside componentWillUnmount.
Sandbox link for your reference: https://codesandbox.io/s/react-basic-class-component-forked-sybv0?file=/src/index.js
Modified Snippet
import React, { Component } from 'react';
class Rando extends Component {
constructor(props) {
super(props);
this.state = { num: 0, color: 'purple' };
this.timer = null;
}
componentDidMount() {
this.makeTimer();
}
componentWillUnmount() {
clearInterval(this.timer);
}
makeTimer = () => {
this.timer = setInterval(() => {
let rand = Math.floor(Math.random() * this.props.maxNum);
this.setState({ num: rand });
}, 10);
}
render() {
return (
<div>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default Rando;
You should call this.makeTimer(); on componentDidMount() instead of constructor
componentDidMount(){
this.makeTimer();
}
Try this code
import React, { Component } from 'react';
class Rando extends Component {
constructor(props) {
super(props); // want to use props insode brackets if we want to use props inside the constructor
this.state = { num: 0, color: 'purple' };
this.makeTimer((data) => {
this.setState(data);
});
}
makeTimer(cb) {
setInterval(() => {
let rand = Math.floor(Math.random() * this.props.maxNum);
cb({ num: rand })
}, 10);
}
render() {
console.log('changing');
return (
<div className=''>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default Rando;
Try this :
import React, { Component } from 'react';
class Rando extends Component {
constructor(props) {
super(props); // want to use props insode brackets if we want to use props inside the constructor
this.state = { num: 0, color: 'purple' };
}
makeTimer() {
setInterval(() => {
let rand = Math.floor(Math.random() * this.props.maxNum);
this.setState({ num: rand });
}, 10);
}
componentDidMount(){
this.makeTimer();
}
render() {
console.log('changing');
return (
<div className=''>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default Rando;

React not rendering an element when used in map() with {} [duplicate]

This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 4 years ago.
React doesn't render the element when I use this form of code:
class ListaPratitelja extends React.Component {
constructor(props) {
super(props);
}
render() {
const items = this.props.pratitelji;
const listItems = items.map((name, index) => {
e(Pratitelj, { key: index, name: name });
});
return listItems;
}
}
I've used a debugger to see what's going on, and the e function (which is just React.createElement) returns undefined.
But it works just fine when I use it like this:
class ListaPratitelja extends React.Component {
constructor(props) {
super(props);
}
render() {
const items = this.props.pratitelji;
const listItems = items.map((name, index) => e(Pratitelj, { key: index, name: name }));
return listItems;
}
}
The question is why? Is this a bug or I did something wrong in the first example. Also this is the full code:
'use strict';
const e = React.createElement;
class ListaPratitelja extends React.Component {
constructor(props) {
super(props);
}
render() {
const items = this.props.pratitelji;
const listItems = items.map((name, index) => e(Pratitelj, { key: index, name: name }));
return listItems;
}
}
class Pratitelj extends React.Component {
constructor(props) {
super(props);
this.state = { deleted: false };
this.handleDeleteChange = this.handleDeleteChange.bind(this);
}
handleDeleteChange(deletedState) {
this.setState({ deleted: deletedState });
}
render() {
console.log("rendered");
if (this.state.deleted) {
return '';
}
return e(
'div',
null,
e(PratiteljIme, { name: this.props.name }),
e(PratiteljDeleteButton, { handleDeleteChange: this.handleDeleteChange})
);
}
}
class PratiteljIme extends React.Component {
constructor(props) {
super(props);
}
render() {
return e(
"span",
null,
this.props.name)
}
}
class PratiteljDeleteButton extends React.Component {
constructor(props) {
super(props);
}
render() {
return e(
"button",
{ type: "button", "onClick": this.props.handleDeleteChange},
"X"
)
}
}
function loadListaPratitelja(pratitelji) {
const lista = pratitelji.split(",");
const domContainer = document.querySelector('#listaPratitelja');
ReactDOM.render(e(ListaPratitelja, {pratitelji: lista}), domContainer);
}
The input variable "pratitelji" is just a string with a couple of CSV (for ex. p1,p2,p3,p4).
The versions of react I use are these:
https://unpkg.com/react#16/umd/react.development.js
https://unpkg.com/react-dom#16/umd/react-dom.development.js
The browser I tested it on is the latest version of firefox for development.
with using { and } you are creating a function that doesn't return anything, unless you return something. Hence .map will return an array filled with undefined.
Update your code to this:
const listItems = items.map((name, index) => {
return e(Pratitelj, { key: index, name: name });
});
If you open up a function after the arrow, you must state what you're returning.

Using an object reference to set initial state in react

While trying to follow the DRY principle I began wondering if the following be encouraged/discouraged in react projects:
const DEFAULT_STATE = {
foo: foobar,
bar: barfoo
}
class Tuna extends Component {
constructor(props) {
super(props)
this.state = DEFAULT_STATE
}
...
reset = () => {
this.setState(DEFAULT_STATE)
}
...
}
or would this be any better (assuming that there are no objects nested inside DEFAULT_STATE)
const DEFAULT_STATE = {
foo: foobar,
bar: barfoo
}
class Tuna extends Component {
constructor(props) {
super(props)
this.state = {...DEFAULT_STATE}
}
...
reset = () => {
this.setState({...DEFAULT_STATE})
}
...
}
or just plain old this (repeating code)
class Tuna extends Component {
constructor(props) {
super(props)
this.state = {
foo: foobar,
bar: barfoo
}
}
...
reset = () => {
this.setState({
foo: foobar,
bar: barfoo
})
}
...
}
thank you.
In any case, you will have no problems if you do not change the initial object. But if you change object may experience the following problems, for example:
const DEFAULT_STATE = {
foo: foobar,
bar: barfoo
}
class Tuna extends Component {
constructor(props) {
super(props)
this.state = DEFAULT_STATE
}
...
reset = () => {
this.setState(DEFAULT_STATE)
}
someFunc = () => {
this.state.foo.push({field: 'lol'})
}
someFuncAfterReset = () => {
console.log(this.state.foo) // always [{field: 'lol'}]
}
}
Except the third case

Questions about React and creating timers when a component is created

I want to create a component that hides itself after a few seconds. I have 2 questions:
Where should I place the setTimeout? Probably in the constructor, componentWillMount, or componentDidMount. Is there a differences in placing it in componentWillMount or componentDidMount?
Is it bad practice to do this.state = ... outside the constructor?
Here's what I have:
class Message extends React.Component {
constructor() {
super();
this.state = {
closed: false,
closeTimeout: null
};
}
componentDidMount() {
if (this.props.closeAfter) {
this.state.closeTimeout = setTimeout(_ => {
this.setState({closed: true});
}, this.props.closeAfter);
}
}
componentWillUnmount() {
if (this.state.closeTimeout) {
clearTimeout(this.state.closeTimeout);
}
}
render() {
return ...
}
};

Categories