I want to initiate my state using local/session storage. Is this approach valid? I tried but it gives me an error. If not, then how can I retrieve a value from the storage directly to my state?
constructor(props) {
super(props);
sessionStorage.setItem('testkey','test value')
this.state = {
abc: sessionStorage.getItem('testkey')
}
}
The error is always undefined.
Also, if I use the other way around, below code works fine
constructor(props) {
super(props);
this.state = {
abc: this.getItems(val)
}
this.getItems = this.getItems.bind(this);
}
getItems(value){
let selectedItem = value;
return selectedItem;
}
But when I do this, it doesn't. I just cannot get the value from my session storage.
constructor(props) {
super(props);
this.state = {
abc: this.getItems(val)
}
this.getItems = this.getItems.bind(this);
}
getItems(val){
let setItem = sessionStorage.setItem('testkey', val);
let getItem = sessionStorage.getItem('testkey');
return getItem;
}
When I log getItem to my console, it gives me an object. What could possibly be the problem?
Im still not too sure what you mean but you definitely have to use this.setState().
this function accepts json {'key':'value'}
once set it updates the state.
You dont actually have to store a function within a state.
I dont know if this was a thing where you use getters and setters.
Set variable values using setState then retrieve them using this.state.[variable_name].
Hope this helps.
class Session extends Component {
constructor(props){
super(props);
this.setValue = this.setValue.bind(this);
this.state = {};
}
setValue(key, value){
let data = {};
data[key] = value;
this.setState(data);
}
render() {
let session = this.state.session;
return (
<div >
<div>{ session }</div>
<input onClick={ ()=> this.setValue('session','Hello') } type="button" value="Click Me" />
</div>
);
}
}
export default Session;
Happy coding.
Related
I've been struggling for hours trying to get some code to work. I'm new with React, but I have spent a lot time looking for a solution to this as well, and updating this code as I understood with no success.
Basically my app is a component that splits into two components, with one of those splitting into 9 buttons. When I click one of those buttons, I want its uncle/aunt to recognize that, and use the id of the button that was pushed to create a message.
I figured I should be passing the button id up to the grandparent so that it can pass the id down to the uncle/aunt. But its the passing the id to the grandparent I'm struggling with.
This is the general set up below:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
"x" : " "
};
getX(x){
this.setState({"x": x})
}
render() {
return (
<div>
<A getX={this.getX}/>
<B x={this.state.x} />
</div>
)
}
}
const A = (props) => {
const getX = (x) => props.getX(x);
a = [];
for (let i=0; i<9; i++) {
a.push(<C id={i} getX={getX}/>);
return <div>{a}</div>
}
class C extends React.Component {
constructor(props) {
super(props);
this.state = {
"id" : props.id,
"getX" : (x) => props.getX(x)
}
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown(e) {
this.state.getX(e.target.id);
}
render() {
<div />
}
}
class B extends React.Component {
constructor(props){
super(props);
this.state = {
"x" : props.x
}
}
render() {
return <div>{this.state.x}</div>
}
}
Firstly, the getX() method of the App component doesn't seem to be working how I expected it to. By that I mean, when I add getX("7"); to the render method of the App component, just before the return statement, the whole thing crashes. But if I replace this.setState({"x": x}) with this.state.x = x in the getX() method, then the state sucessfully passes down to the component B, which is something at least. But, I don't understand why.
Secondly, I can't work out how to modify the App component's state from within component A. The getX() method of the App component doesn't seem to be passed into component A as I expected. Again, if I insert getX("7"); before the return statement of component A, the whole thing crashes again. I expected the getX function of component A to be the same function as the getX method of the App component, and therefore update the state of the App component. But I've had no success with that at all. I've even tried inserting this.getX = this.getX.bind(this) into the constructor of the App component, but that didn't solve everything for me.
Lastly, as you can probably guess, I cant modify the App component's state from any of the C components.
Any ideas? I'm stumped.
I have modified your example so that it works. A few things:
Dont copy props to state, that is an antipattern and creates bugs (as you have seen). Dont copy the id or the function passed from component A to component C, or in component B. Just use the props values.
You had some syntax errors that I fixed.
You didnt return the array created in component A.
(This is my preference, but I will argue that you are setting a value, not getting, so i renamed getX to setX.)
There was nothing returned from component C. I was not sure what you was suppoosed to be returning from that component, so I just created a button with a click-handler.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
x: '',
};
this.setX = this.setX.bind(this);
}
setX(x) {
this.setState({ x: x });
}
render() {
return (
<div>
<A setX={this.setX} />
<B x={this.state.x} />
</div>
);
}
}
const A = (props) => {
let a = [];
for (let i = 0; i < 9; i++) {
a.push(<C id={i} setX={props.setX} />);
}
return <div>{a}</div>;
};
class B extends React.Component {
render() {
return <div>{this.props.x}</div>;
}
}
class C extends React.Component {
constructor() {
super();
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown() {
this.props.setX(this.props.id);
}
render() {
return <button onClick={this.handleMouseDown}>Click me</button>;
}
}
I'm exploring state in ReactJS and encountered this problem. What I want to happen is when the state === 0 it will go back to its original value. Here's my code:
export default class Test extends React.Component {
constructor (props) {
super(props);
this.state ={
stateValue: 5
}
}
And inside componentDidUpdate() is I decrement the value of state by 1 and have a condition in setState but I don't know what to put inside setState in order for the state to come back to its original value again.
if (stateValue === 0) {
this.setState({ })
}
and inside return is
<div>
<h1>{stateValue}</h1>
</div>
The result is it counts from 5 down to 0 but when it gets 0. It doesn't change back to its original value.
What I want to happen is when it turns to 0 it will go back to its value again which is 5 then continue to count down again. How can I do this? Thanks in advance
You can store another property in your set state.
export default class Test extends React.Component {
const originalValue = 5;
constructor (props) {
super(props);
this.state ={
stateValue: originalValue
}
}
}
And then while updating you can assign that property
if (stateValue === 0) {
this.setState({ stateValue: originalValue })
}
You can impliment this kind of logic with initial state with class property:
class Example extends Component {
defaultState = {
stateValue: 5,
};
constructor(props) {
super(props);
this.state = this.defaultState;
}
componentDidUpdate(_prevProps, _prevState) {
if (this.state.stateValue === 0) {
this.setState(this.defaultState);
}
}
render() {
const { stateValue } = this.state;
return (
<div>
<h1>{stateValue}</h1>
</div>
);
}
}
I just update to the react 16.3. I have a value to keep tracking of a value that I need to post to the server. I want to save this.value after some props changed. I found out that a lot of life cycle functions are deprecated. And I cannot save the value into redux before rendered. Could anyone give me a good way to handle it? Thanks.
class Foo extends Component {
constructor(props) {
super(props);
this.value = {};
}
render() {
return (
//some other components
<Bar onChange={value => this.value = value} />
)
}
}
I would most likely handle it with this
class Foo extends Component {
state = {
text: ''
}
render() {
return (
//some other components
<Bar onChange={value => this.setState({text:value})} />
)
}
}
Keep in mind this is ES7 way to do it. A bit cleaner than doing it in constructor(). If you don't use new syntax just initiate state in constructor as,
constructor(props){
super(props)
this.state = {
text: ''
}
}
if you would like to get your hands dirty more with handling value that user is giving could also pass onChange value to own function and setState on there. Many prefer it that way.
e.g.
handleChange = (text) => {
// Some amaizing text manipulation
this.setState({text})
}
render() {
return (
//some other components
<Bar onChange={this.handleChange} />
)
}
and with redux dispatch function
constructor(props) {
super(props)
/**
* Bind funtions
*/
const { dispatch } = props
this.patchReservation = params =>
dispatch(ActionCreators.patchReservation(params))
}
Then you just attach e.g. this.patchReservation to onChange -listener. ActionCreators is one of my import's which contains my Redux action -functions.
Cheers!
My parent component is like this:
export default class MobileCompo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
datasets: {}
};
this.get_data = this.get_data.bind(this);
}
componentWillMount() {
this.get_data();
}
async get_data() {
const ret = post_api_and_return_data();
const content={};
ret.result.gsm.forEach((val, index) => {
content[val.city].push()
});
this.setState({data: ret.result.gsm, datasets: content});
}
render() {
console.log(this.state)
// I can see the value of `datasets` object
return (
<div>
<TableElement dict={d} content={this.state.data} />
<BubbleGraph maindata={this.state.datasets} labels="something"/>
</div>
)
}
}
child component:
export default class BubbleGraph extends React.Component {
constructor(props) {
super(props);
this.state = {
finalData: {datasets: []}
};
console.log(this.props);
// here I can't get this.props.maindata,it's always null,but I can get labels.It's confusing me!
}
componentWillMount() {
sortDict(this.props.maindata).forEach((val, index) => {
let tmpModel = {
label: '',
data: null
};
this.state.finalData.datasets.push(tmpModel)
});
}
render() {
return (
<div>
<h2>{this.props.labels}</h2>
<Bubble data={this.state.finalData}/>
</div>
);
}
}
I tried many times,but still don't work,I thought the reason is about await/async,but TableElement works well,also BubbleGraph can get labels.
I also tried to give a constant to datasets but the child component still can't get it.And I used this:
this.setState({ datasets: a});
BubbleGraph works.So I can't set two states at async method?
It is weird,am I missing something?
Any help would be great appreciate!
Add componentWillReceiveProps inside child componenet, and check do you get data.
componentWillReceiveProps(newProps)
{
console.log(newProps.maindata)
}
If yes, the reason is constructor methos is called only one time. On next setState on parent component,componentWillReceiveProps () method of child component receives new props. This method is not called on initial render.
Few Changes in Child component:
*As per DOC, Never mutate state variable directly by this.state.a='' or this.state.a.push(), always use setState to update the state values.
*use componentwillrecieveprops it will get called on whenever any change happen to props values, so you can avoid the asyn also, whenever you do the changes in state of parent component all the child component will get the updates values.
Use this child component:
export default class BubbleGraph extends React.Component {
constructor(props) {
super(props);
this.state = {
finalData: {datasets: []}
};
}
componentWillReceiveProps(newData) {
let data = sortDict(newData.maindata).map((val, index) => {
return {
label: '',
data: null
};
});
let finalData = JSON.parse(JSON.stringify(this.state.finalData));
finalData.datasets = finalData.datasets.concat(data);
this.setState({finalData});
}
render() {
return (
<div>
<h2>{this.props.labels}</h2>
<Bubble data={this.state.finalData}/>
</div>
);
}
}
For example I have a store:
class MyStore {
constructor() {
this.value = 1;
}
}
I need to get and change MyStore.value in a view.
I can do it:
class MyView extends React.Component {
constructor() {
super();
this.state = {
value: MyStore.getValue()
};
}
And change it:
userClick() {
this.setState({value: MyStore.changeValue('newValue')});
}
Or change value in a store and call emit.
But I can do it with forceUpdate():
render() {
const value = MyStore.value;
return (
<div>{value}</div>
)
}
And change it:
userClick() {
MyStore.value = 'newValue';
this.forceUpdate();
}
Why is it bad?
I don't think there is anything wrong in what you are trying to do. You are "just" following basic OO-rules and are encapsulating your data.
Actually I don't understand why most basic React examples don't introduce this pattern, instead of mixing data and presentation. Usually you don't see stuff like stores before you reach examples involving, Flux, Redux or MobX (which I think is the way for you to go).
I have rewritten your example in this codepen to use getters and setters and I'm using the observer pattern to notify when data has changed.
I would claim that this (remember it's a quick demo) is a perfectly OK way to use forceUpdate().
class MyView extends React.Component {
constructor(props) {
super(props);
this.props.store.setObserver(this);
}
changed(){
this.forceUpdate();
}
render() {
return (
<div>
<button onClick={()=>this.props.store.value = Math.random()}>Change</button>
<p>{this.props.store.value}</p>
</div>
)
}
}
class MyStore {
constructor() {
this._value = 1;
}
get value() {
return this._value;
}
set value(val) {
console.log(val);
this._value = val;
this._observer.changed();
}
setObserver(observer){
this._observer = observer;
}
}
Actually this is what the mobX library is doing under the surface. It provides you with automatic listener-capacities, and if this is the way you plan to go I definitely advice you to take a look at this library.
It will handle all the "observer" details, including forceUpdate() automatically (it does not use forceUpdate, but calls your render() method when an updata is required).
With mobX the example boilds down to (using a functional component, since it does not need state)
var View = observer((props) => (
<div>
<button onClick={()=>props.store.value = Math.random()}>Change</button>
<p>{props.store.value}</p>
</div>
)
)
class MyStore {
#observable value =1;
get value() { return this._value; }
set value(val) { this._value = val; }
}
Se live demo on codepen.io