I just started working with React Native two weeks ago and I hit a wall.
I'm working on an IoT project that is logging things like temperature, humidity, CO levels etc..
I also decided to create an app to display these parameters inside a real-time chart. So far, I figured out how to communicate with the server and get data on demand and how to draw charts. The only problem is, how do I make the x-axis (time axis) dynamic? I want to update the graph every few seconds (let's say 5) when I make a new request for parameters to the server.
I've never done anything similar and I'm new to React so I have no idea how to handle this. I'd love if anyone could show a quick example in React Native with dynamic x-axis, even if it's with randomly generated numbers.
And oh, how do I get current time? I want it in a format like hours:minutes.
Thank you!
There are many ways to implement this depending on how you're getting data from the server and what library you're using to plot out data. I'll try to give as generic of an answer as I can.
Let's assume you have a function called getXAxisValueFromServer which will asynchronously request the value you want from your server and return it in a callback. (This is assuming your application queries data from the server periodically. If your application is reactive and receives data from the server through something like an Rx.js observable, the logic would be the same but you would put it in the observable's data callback)
To make your component render this dynamically, you need to make your component re-render whenever a new value arrives.
A React component re-renders under exactly two conditions: when its state changes, and when its props change.
Therefore, in order to have your component dynamically update, you'll need to tie your data to its state or its props.
In general, when using React, it's a good idea to keep presentation separated from logic. So the best approach to this would be to create a "smart" container component which receives data from the server and keeps that data in its state, and a "dumb" presentation component which renders the received data. Let's assume we have a chart which correctly plots data implemented as the Chart component, which receives a prop called data. We now want to implement a ChartContainer which will query the server for data periodically and update the Chart:
import React, { Component } from 'react';
import { getXAxisValueFromServer } from './server-api';
import Chart from './chart';
export default class ChartContainer extends Component {
constructor(props) {
super(props);
this.state = { data: null };
this.intervalHandle = null;
}
componentDidMount() {
this.intervalHandle = setInterval(() =>
getXAxisValueFromServer((data) => this.setState({ data })),
3000); //this is just an example - here we try to update
//the data every 3 seconds
}
render() {
return (
<Chart data={this.state.data} />
);
}
}
So here, we have created an example container which will query the server for new data every 3 seconds and update the chart with the received data when the server returns it. You should be able to adapt this to your use case.
Related
I am using a 3rd party library to generate a sortable grid that expects to be fed JSON data, is there a way to send part of the redux store to this non-react grid other than as a react component, attribute or innerHtml since it does expect JSON? The challenges are that all my redux scripts are modules which is a scoping issue since, in this case, the 3rd party element is wrapped in asp.net so I can't expose it to a function (though it can call a javascript function to get the data), and that I need to be able to subscribe to changes, this has proven unnecessarily difficult so far.
You can just call store.getState() to get the current state of the store.
You may want to attach the store on to the window to give it global scope when you create it,
window.redux = { store }
or if using modern js, create a wrapper export function in the file that you create it
export const getStore = () => store
So that you can then do
getStore().getState()
If I understand your question correctly, you are using some third-party element in a react app that takes data in the form of JSON? Without more details on the third-party library its hard to give a proper answer but I'll give it a shot.
Whatever this library is, you have to render it somehow at some point. Since we don't know what you are using I am going to pick jQuery.
Assume the following usage
$("#grid").initializeGrid(data);
You can expect the react component to be something like
const GridWrapper = (props) => {
const tableData = useSelector(selectTableJson);
useEffect(() => {
$("#grid").initializeGrid(data);
}, [tableData]);
return (
<div id="grid" />
);
}
Basically what is happening is you select the data from the redux store, and then initialize the third party component with that data.
First off some description of what I need to achieve. I show information in front-end (React) that mostly corresponds to database rows and the user can do regular CRUD operations on those objects. However, I also add some dummy rows into the JSON that I send to front-end because there are some objects that are "defaults" and should not be inserted into the database unless the user actually wants to modify them. So what I need to do is once a user wants to modify a "default" object in front-end, I first have to POST that object to a specific endpoint that copies it from constants to the database and only then follow that up with the request to modify that row.
Secondly, the architecture around this. For storing the state of the rows in front-end I'm using Redux via easy-peasy and I have a thunk for doing the first saving before modifying. Once a user wants to edit a "default" object anywhere in the UI (there are about 20 different ways of editing an object), the flow of the program looks something like this:
User edits something and presses "save"
Thunk is called in the save function and awaited
Thunk POSTs to backend to insert the object into database and return the corresponding row
Backend responds with the ID-s of the rows
Thunk calls action and updates these objects in store with correct ID-s
Thunk returns and the function pointer moves back to the modifying function
The modifying function makes another request with the correct ID-s
The modifying function updates the store with the modified values
Now, the problem I run into is from step 5 to 7, because the component looks basically like this:
const Foo = () => {
const insertToDatabaseIfNecessary = useStoreActions((actions) => actions.baz.insertIfNecessary)
const items = useStoreState((state) => state.baz.items);
const onSave = async () => {
await insertToDatabaseIfNecessary();
// do the actual modifying thing here
axios.post(...items);
}
return (
<button onClick={onSave}>Save!</button>
);
}
If you know functional components better than I do, then you know that in onSave() the insertToDatabaseIfNecessary() will update the values in Redux store, but when we get to the actual modifying and post(...items) then the values that are POSTed are not updated because they will be updated in the next time the component is called. They would be updated if this was a class-based component, but easy-peasy has no support for class-based components. I guess one way would be to use class-based components and Redux directly but I have feeling there might be a different pattern that I could use to solve my issue without resorting to class-based components.
The question: Is there a sane way of doing this with functional components?
Thunks in easy-peasy can handle asynchronous events, so you should put your axios post in there e.g.
insertToDatabaseIfNecessary : thunk(async (actions, payload) => {
// First update the data on the server
await axios.post(payload.items);
// Assuming that the post succeeds, now dispatch and action to update your store.
// (You'd want to check your post succeeded before doing this...)
actions.updateYourStoreData(payload);
})
This easy-peasy thunk will wait for the async post to finish, so you can use the action as follows in your Foo component:
insertToDatabaseIfNecessary();
You will not need to await it or use the onSave function in your Foo component.
I'm plotting real time data of accelerometer of mobile against time axis.x-axis will have time and y-axis will show values of accelerometer. I'm using react-native-highcharts for plotting data. But the output graph is blank. The code for live data plot is given at the URL https://github.com/TradingPal/react-native-highcharts . In this code I'm just replacing y with x-values of accelerometer.
output is:
You are mutating state, which is a big no-no in React.
State should be immutable at all times, and only changed via a call to setState. If you are just directly mutating it like in your example, your component will not update.
I would advise you to learn more about component state in React (same in React Native) then you will realize how you can refactor your calls to this.state.dataArr.push and such.
render should be a pure function of props and state.
As we don't see the entire picture, only the render method (in the future please try to post a complete example) we can only make assumptions here.
I would imagine that in some of your other code you are recording the accelerometer and call setState to change accelerometerData. (If you are directly changing it via a regular assignment, change it to a setState call.) Then instead of mutating dataArr in the render method, change dataArr using the same setState call.
p.s. This is still not a perfect solution as it would still be using derived state, but that is another - and slightly more advanced - topic to talk about.
Your code as it is, always uses the latest Accelerometer data, i.e. you're always plotting one point (latest), and so the graph seems empty.
What you should do, make accelerometedData an Array in your state definition and then in subscribe push the data to it, instead of setting the latest point using setState, and plot from it to plot multiple points.
EDIT
To clarify:
Your state should be something like
state = {
accelerometerData: []
};
Then your subscribe would be:
_subscribe = () => {
this._subscription = Accelerometer.addListener(accelerometerData => {
let data = this.state.accelerometerData;
data.push(accelerometerData);
this.setState({
accelerometerData: data
});
});
};
And then inside render() you have this.state.accelerometerData which is arrray that you can use via this.state.accelerometerData.map() or similar
My understanding of state variables in React is that only data that changes as a result of user interaction or asynchronous data flow should be stored in state. What if I need to request list data from several APIs and then combine these to make a new master list to serve as a constant source of truth that may need to be used by various component methods during phases of user interaction? What is the correct place to store unchanging data like this? It's tempting to put this data in state for easy access but that doesn't seem right. Thanks.
You don't need to use redux, in this case. It's OK to save your API data call to state, even though the data won't change. If you don't want to save it to state you can save it to a static or global variable.
class App extends React.Component {
API_DATA = []; // save data here
state = {
api_data: [] // it's ok too
}
componentDidMount = () => {
// call to api
// save data to API_DATA
this.API_DATA = data;
}
}
This is where something like React hooks or Redux would come in handy. If you're unfamiliar, both can be used to globally store state. Redux would be better for high frequency changes but it sounds like hooks would be best for your situation.
There are plenty of tutorials out there for this on Youtube, the React subreddit, etc.
This question is more to know your opinions about the way I'm trying to solve this issue.
I would need a little bit of ReactJs expertise here as I'm quite new.
First a little bit of context. I'm developing a web application using ReactJs for the frontend part.
This webapp is going to have many translations, so for maintenance I thought it would be better to store all the translations in a database instead of having them into a file. This way I could manage them using sql scripts.
I'm using a MySQL database for the backend, but for performance reasons, I have added ElasticSearch as second database (well, it is more a full text search engine).
So once the application starts, the translations are automatically loaded into ElasticSearch. Every translation has a code, and a text, so in elastic search I only load the translations for one locale (by default english), and when a user switchs the locale, a call is done to load all the translations for the selected locale and update their corresponding text.
This way from the fronted I can reference a translation only by the code and I will get the text translated in the correct locale.
Now, how do I do that in react?
So far I have written a component TranslatedMessage which is basically looking for a given code and displaying it whereever this component is rendered.
Below the code of the component:
import React from 'react';
export class TranslatedMessage extends React.Component {
constructor() {
super();
this.render = this.render.bind(this);
this.componentDidMount = this.componentDidMount.bind(this);
this.state = {message: ''};
}
render() {
return (<div>{this.state.message}</div>);
}
componentDidMount() {
var component = this;
var code=this.props.code;
var url="data/translation?code="+code;
$.get(url, function (result) {
component.setState({message: result.text});
});
}
};
And then I use it in the application whis way, for example to translate the title of an 'a' link:
<TranslatedMessage code="lng.dropdown.home"/><i className="fa fa-chevron-down" />
So far is working fine but the problem is that I need to refresh the whole page to get the new translations displayed, because I'm not updating the state of the component.
So now my questions:
1)Every time that we find in a page the component TranslatedMessage, a new instance of that component is created right? so basically if I have 1000 translations, 1000 instances of that component will be created? And then React has to take care and watch all these instances for changes in the state? Would that be very bad for performance? Do you find any more efficient way to do it?
2) I don't think forcing the whole page to reload is the most proper way to do it, but how can I update the states of all that components when a user switch the locale? I've been reading about a framework (or pattern) called Flux, and maybe that could fit my needs, what do you thing, would you recommend it?
3) What do you think about storing translations on db, I'm a bit concern about sending a query to the db for every translation, would you recommend or not this approach?
Any suggestions, ideas for improvement are very welcome!
Thank you for taking your time to read it or for any help!
I use what is basically a Flux store for this purpose. On initialisation the application requests the whole language file to use (which is JSON) and that gets shoved into memory in the store, something like this (I'm going to assume a totally flat language file for now, and I'm using ES2015/16 syntax, I've omitted error checking etc etc for brevity):
class I18n {
constructor() {
this.lang = await fetch( 'lang_endpoint' )
.then( res => res.json() )
}
get( translation ) {
return this.lang[ translation ] || null
}
}
Somewhere my app starts during a ReactDOM.render( <App /> ) or some variation and this renders the whole thing top-down (I try to eliminate state as much as possible). If I needed to switch languages then I'd bind a change handler such that the store emits a change event which is heard by some code that triggers a ReactDOM.render. This is fairly standard Flux practise for changing the app state, the key is to try and eliminate state from your components and store it inside your stores.
To use the I18n class simply instantiate it somewhere (I normally have it as a singleton exported from a file, e.g. module.exports = new I18n(), require that file into your components and use the get method (this assumes some sort of packager such as browserify or webpack but it looks like you have that complexity all sorted):
import 'i18n' from 'stores/i18n'
class MyComponent extends React.Component {
constructor() { ... }
render() {
return (
<span>{ i18n.get( 'title' ) }</span>
)
}
}
This component could also be simplified to
const MyComponent = props => <span>{ i18n.get( 'title' ) }</span>