How to keep value displayed after reloading of the page? - reactjs

I have a React.js application and it connects and subscribes to an MQTT broker. Initially, it gets the value from the broker properly but if I reload the page, it first shows me 0 and then it has to wait for this value to be received again from the broker so it will not get its actual value until the subscribe is notified for a change.
What I want is that after reloading of the page, I can still see the value before that. How can I do that?
Thanks in advance.
Here is my code:
render() {
//access range from redux store via props
const {rangeEstimate} = this.props
//if range is not null - show it, otherwise - show no data
const rangeValue = rangeEstimate && rangeEstimate>=0 ?
(<div>
{rangeEstimate.toString()}
</div>)
: (<div>0</div>)
if(rangeEstimate>=0 && rangeEstimate) {
localStorage.setItem('rangeValue', rangeEstimate);
}
const {battery} = this.props
//if battery is not null - show it, otherwise - show no data
const batteryValue = battery && battery>=0 ?
(<div>
{battery +"%"}
</div>)
: (<div>0%</div>)
return (
<StyledRangeContainer className="RANGE">
<div>
<StyledRangeText>{rangeValue}</StyledRangeText>
</div>
<StyledBatteryCapacityValue>{batteryValue}</StyledBatteryCapacityValue>
</StyledRangeContainer>
);
}
}
//map this component's state to props from redux store
const mapStateToProps = (state) => {
return {
rangeEstimate:state.rangeEstimate,
battery:state.battery
}
}
//connect this component to Redux
export default connect(mapStateToProps,null) (RangeEstimate)

Assuming you have control over the MQTT publisher, publish the value with the retained bit set.
That means that when ever a client subscribes to the topic, the last published value will be delivered by the broker immediately. The next published message (with the retained bit) will then replace this stored value.

In most software engineering, we set initial or starting values in the constructor. So, let's add one and use it in your class. I'm assuming it's a ReactJS class, because you are using a render() method. Here's your constructor...
constructor(props) {
super(props);
this.state = {
'rangeValue':localeStorage.getItem('rangeValue'),
'batteryValue':localeStorage.getItem('batteryValue'),
};
}
Notice I am populating the state with the results of localeStorage.getItem().
Then you need to update your render() to be based on the state...
return (
<StyledRangeContainer className="RANGE">
<div>
<StyledRangeText>{this.props.rangeValue ? this.props.rangeValue : this.state.rangeValue}</StyledRangeText>
</div>
<StyledBatteryCapacityValue>{this.props.batteryValue ? this.props.batteryValue : this.state.batteryValue}</StyledBatteryCapacityValue>
</StyledRangeContainer>
);
Of course, you'll want to use the prop value if it's there, so this code reflects that, by checking the props. You may want this to check a variable, but that would work, too.

Related

How to see changes made to buttons in react without having to refresh page?

I have a series of buttons mapped from an API list. When pressed, the buttons change a users rank value. however I want it so that a user can not assign a lower rank than the one they currently have, so I have made it so that the buttons disable if the key value is lower than the current rank key value. the functionality works, however you only see the buttons become disabled if you refresh the page.
export default class rankChangeButtons extends React.Component{
constructor() {
super()
this.state = {
data: [],
rankId: this.props.rankId,
rank: this.props.rank,
}
this.updateRank = this.updateRank.bind(this);
}
getData = () => {
//this is where I call the API
data: res.data
}
updateRank(element) {
const { id, value } = element.target;
let headers: any = {"rankingList": this.props.rankingListId, "Content-Type" : "application/json"};
var payload = {"rankId":id,"affiliationId":this.props.affiliationId};
saveRankChange(payload, headers).then(()=>{
//call buttonAction function on parent component.
this.props.buttonAction(
id, value
)
//id and value are passed to parent to update rank
}).catch((e: any)=>{})
}
render() {
return(
<div>
<h5>User Rank:</h5>
<div className='buttonContainer'>
{this.state.data.map((rank =>
<li key={rank.key}>
<button id={rank.key} value = {rank.text} onClick={this.updateRank} disabled={rank.key <= this.state.rankId ? true : false}>
{rank.text}
</button>
</li>
))}
</div>
</div>
)
}
}
}
I would like to know if there is a way to see which buttons are disabled after changing the value without having to refresh the page.
Are you sure that this.updateRank is changing states?
Because according to react docs, if there's a state change, then the render method is called again with this.state updated.
You could see the button getting disabled if one of these options actually happened:
this.updateRank updates this.state.rankId.
this.updateRank calls a function that changes the property rank on the item you need on this.state.data.
If everything is fine, then show us this.updateRank code or how exactly the update happens.

React can not access variable from return

I am very new to React and I can not solve this issue for a very long time. The idea is the following, I get some user info from database and pass it into cookies. From react side I get this cookies as JSON object and I need to render menu for user depending on values in this object. Right now I pass this object that I get from cookies from parent Component and I try to access it from Settings component. The issue is that I can see access this object from test function, however when I try to access this data from return it gives me undefined error. The function that returns value from cookies is sync, I have no idea why that might happen, please help.....
Since this.state.shopSettings["new_orders"] is boolean, use ternary.
Don't copy props to the state inside constructor as the constructor is executed only once. So updates to the props won't be reflected in the component.
Like this
<button onClick={this.test}>
{props.shopSettings && (props.shopSettings["new_orders"] ? 'true button' : 'false button')}
</button>
It solves very easily with this code, now I can access any key from shopSettings inside return without any issues
class Index extends React.Component {
state = {
shopSettings: Cookies.getJSON('shopSettings')
}
render() {
const {shopSettings} = this.state
if (!shopSettings) {
return null
}
return (
<div>Hello</div>
)
}

React App: how to pass a variable to other file and read its value there

I am building on sample 16 from Github/Webchat to build a webpage with a webchat interface.
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/16.customization-selectable-activity
The react app consists off different .js files to build the website( Webchat.js, Instuctor.js, App.js, Index.js) and I can't provide file Inspector.js with the data I gathered in file Webchat.js.
I can't find the right code to read the value of a variable from file Webchat.js in file Inspector.js.
I want to build a Webpage where I have on the left side a Chatbot (BotFrameWork) running, and next to it a table running which shows data that has been collected by the chatbot.
I tried answers from
how to get a variable from a file to another file in node.js
but doesn't work.
I tried to get the state of Webchat but gives only undefined.
Example:
(webchat.js) I fetched data from the bot (like [link]How to create a side window or iframe that shows data that was gathered by a Web-Chat in one web page?) and saved it in a state variable 'test'.
(instructor.js) I want to show that data e.g. in a label that is getting updated when new data comes in. How do I get access now to the value of 'test' that is created in another file?
What doesnt work:
in instuctor.js:
var test2 = require ('./webchat');
Console.log(test2.state.test) //this is how I imagine it to work --> undefined
with require I only get an object that has a 'name' variable 'Webchat' and which i can get out with: console.log(test2.default.name);
React only supports one-way data binding, so if you want to share a variable between multiple components, you need to elevate the state to the parent and pass the variable and change handlers to the children as props.
In the example below, Parent has two children: ChildA and ChildB. We could keep myValue in ChildA's state, but then ChildB wouldn't be able to access it, so we elevate myValue to the parent and pass it to both children as props. We also, pass a change handler to ChildB so it can update the value when the user clicks it.
import React from 'react';
const ChildA = ({ myValue }) => (
<div>
{
myValue
? <h1>Hello World</h1>
: <h1>Goodbye!</h1>
}
</div>
);
const ChildB = ({ myValue, handleMyValueChange}) => (
<button onClick={ () => handleMyValueChange(false) } disabled={ myValue }>
Click Me!
</button>
);
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { myValue: true }
}
render() {
return (
<div>
<ChildA myValue={this.props.myValue}/>
<ChildB myValue={this.props.myValue} handleMyValueChange={ handleMyValueChange }/>
</div>
)
}
handleMyValueChange = myValue => {
this.setState({ myValue });
}
}
In terms of the sample you referenced, the parent class is App and the two children are ReactWebChat and Inspector. I would recommend elevating the state of your variable to the parent - App - and pass it as a prop to the Inspector class. Then you can add a custom store middleware to ReactWebChat that updates your variable when the bot sends an update event. For more information on how to configure your bot to send update events and how to make Web Chat listen for them, take a look at this StackOverflow Question.
Hope this helps!

Preserve internal state on page refresh in React.js

It must be pretty regular issue.
I'm passing props down to the children and I'm using it there to request to the endpoint. More detailed: I'm clicking on the list item, I'm checking which item was clicked, I'm passing it to the child component and there basing on prop I passed I'd like to request certain data. All works fine and I'm getting what I need, but only for the first time, ie. when refreshing page incoming props are gone and I cannot construct proper URL where as a query I'd like to use the prop value. Is there a way to preserve the prop so when the page will be refresh it will preserve last prop.
Thank you!
(You might want to take a look at: https://github.com/rt2zz/redux-persist, it is one of my favorites)
Just like a normal web application if the user reloads the page you're going to have your code reloaded. The solution is you need to store the critical data somewhere other than the React state if you want it to survive.
Here's a "template" in pseudo code. I just used a "LocalStorage" class that doesn't exist. You could pick whatever method you wanted.
class Persist extends React.Component {
constuctor(props) {
this.state = {
criticalData = null
}
}
componentDidMount() {
//pseudo code
let criticalData = LocalStorage.get('criticalData')
this.setState({
criticalData: criticalData
})
}
_handleCriticalUpdate(update) {
const merge = {
...LocalStorage.get('criticalData')
...update
}
LocalStorage.put('criticalData', merge)
this.setState({
criticalData: merge
})
}
render() {
<div>
...
<button
onClick={e => {
let update = ...my business logic
this._handleCriticalUpdate(update) //instead of set state
}}
>
....
</div>
}
}
By offloading your critical data to a cookie or the local storage you are injecting persistence into the lifecycle of the component. This means when a user refreshes the page you keep your state.
I hope that helps!

If/Guard Clauses in React/Redux Components

I have a React component that is being rendered and some initial data isn't available just yet. Because of that, I have these two if blocks (guard clauses) that check to see if we're in a state to even bother rendering. Basically, when this component is used, we're in a state where we have header records for the data, but none of the detail records yet. So this component is recognizing that and retrieving the detail before displaying.
This feels wrong, like this isn't the way it should be done in React/Redux. Further, that second if block could possibly cause an infinite loop. It basically checks to see if we have detail data for a header record. If not, we return and call props.onSortItemChanged() to begin the process of fetching the data. What if the data doesn't exist? Then we'd come back here and make the call again. Anyway, that's just one issue.
The main issue is that I believe a component like this shouldn't know or care about having to fix/retrieve data. It should just display with data that's already in a correct form. Is that right? If so, where is the right place to check and make sure the data is in good form? The action? The reducer?
render() {
const {
printSortOptions,
printSortDetails,
selectedPrintSortOption,
printSortDrawerEvent
} = this.props;
if (printSortDrawerEvent === printSortDrawerEventTypes.CLOSE ||
printSortDrawerEvent === printSortDrawerEventTypes.FAIL) {
return <div id="emptyDiv" />;
}
if (printSortOptions && printSortDetails.length === 0) {
const selectedOptions = printSortOptions.filter(o => o.isDefault);
this.props.onSortItemChanged(selectedOptions[0]);
return this.constructor.loadingJsx();
}
const selectedPrintSortDetails = printSortDetails.filter(
d => d.printSortOption.printSortId === selectedPrintSortOption.printSortId)[0];
return (
<div className="col-xs-12">
// remaining JSX here
)
}

Resources