ReactJS values of Const on div - javascript

I'm new on react and have a simple application as this:
My purpose for this app it's to consume an Spring Boot REST Service and print the data json on my react app.
I achieve this following this tutorial: https://github.com/marmelab/restful.js/tree/master
But now I'm stuck on a simple problem, don't know how to print the values on a html tag, this is an example of my code:
import React from 'react';
import request from 'request';
import restful, { requestBackend } from 'restful.js';
const api = restful('http://someUrl/v1/mobile', requestBackend(request));
const totals = api.one('statusOrders',1); //organizationID = 1
totals.get().then((response) => {
const requestBody = response.body();
const totalsOrders = requestBody.data(); /*Need to print this on the <div>**/
})
class RestGps extends React.Component {
render(){
return(
<div className="container">
<p>Hello World</p>
//Here I want to print the values.
</div>
)
}
}
export default RestGps
The const totalsOrders has the values of the request, the request structure it's like this:
{
"remissionOk": 109,
"remissionAlert": 5,
"remissionError": 17,
"remissionOutOfTime": 82
}
¿Can someone please tell me how can I print this totalsOrders on my html as my text "Hello World"? Regards.

First you need to change some things around.
Your totalOrders object needs to be within the scope of your RestGps class.
You aren't using states, which can cause a lot of weird behaviour!
I suggest doing the following:
import React from 'react';
import request from 'request';
import restful, { requestBackend } from 'restful.js';
const api = restful('http://someUrl/v1/mobile', requestBackend(request));
const totals = api.one('statusOrders',1); //organizationID = 1
class RestGps extends React.Component {
state = { text: "loading ..." };
componentDidMount = () => {
totals.get().then((response) => {
const requestBody = response.body();
const totalsOrders = requestBody.data(); // assuming this is object
this.setState({ text: JSON.stringify(totalsOrders) });
})
}
render = () => {
return(
<div className="container">
<p>{this.state.text}</p>
//Here I want to print the values.
</div>
)
}
}
export default RestGps
Why are using states?
Well. Initially, your component won't have any data to show. This is because get takes time to fetch remote resources.
So what will tell react to re-render your component, to show the text once the resource gets loaded? Nothing! This is why you need to use states.
What is componentDidMount?
componentDidMount is a function part of the react lifecycle. It is called when the component initially gets rendered. When it renders, you want to fetch the resource, then update our state.
How do we pass the string into the paragraph element?
This is simple, you can just reference your state in the render function, using this.state.text, then add it as a text node in <p>

You can make use of life cycle methods.
class RestGps extends React.Component {
state = {
totalsOrders : null,
};
componentDidMount() {
const api = restful('http://someUrl/v1/mobile', requestBackend(request));
const totals = api.one('statusOrders',1); //organizationID = 1
totals.get().then((response) => {
const requestBody = response.body();
const totalsOrders = requestBody.data(); /*Need to print this on the <div>**/
this.setState({totalsOrders: totalsOrders });
})
}
render(){
const {totalsOrders} = this.state;
return(
<div className="container">
<p>Hello World</p>
totalsOrders.map(item => {
{item}
});
</div>
)
}
}

Related

React call functions on renderless component

I need to have a component for handling settings, this component (called Settings) stores state using useState(), for example the primary color.
I need to create a single instance of this component and make it available to every component in the app. Luckily, I already pass down a state dict to every component (I'm very unsure if this is the correct way to achieve that btw), so I can just include this Settings constant.
My problem is that I don't know how to create the component for this purpose, so that I can call its functions and pass it to children.
Here is roughly what my Settings component looks like:
const Settings = (props) => {
const [primaryColor, setPrimaryColor] = useState("")
const getColorTheme = (): string => {
return primaryColor
}
const setColorTheme = (color: string): void => {
setPrimaryColor(color)
}
return null
}
export default Settings
Then I would like to be able to do something like this somewhere else in the app:
const App = () => {
const settings = <Settings />
return (
<div style={{ color: settings.getColorTheme() }}></div>
)
}
Bear in mind that I'm completely new to react, so my approach is probably completely wrong.
You can use a custom Higher Order Component(HOC) for this purpose, which is easier than creating a context(even thougn context is also a HOC). A HOC takes a component and returns a new component. You can send any data from your HOC to the received component.
const withSettings = (Component) => {
const [settings, setSettings] = useState({})
// ...
// ...
<Component {...props} settings={settings}/>
);
And you can use it like this:
const Component = ({ settings }) => {
...your settings UI
}
export default SettingsUI = withSettings(Component);
You can read more about HOCs in the official react documentation

Convert class component to functional components using hooks

I am trying to convert this class component to functional component using hooks
import React, { Component, cloneElement } from 'react';
class Dialog extends Component {
constructor(props) {
super(props);
this.id = uuid();
}
render(){
return ( <div>Hello Dialog</div> );
}
}
This component is initiated with a specific ID because I may have to use multiple instances of them. How can I achieve this if I use functional component?
One solution would be to use useEffect to create your ID at the first render, and store it in the state :
const Dialog = () => {
const [id, setId] = useState(null);
useEffect(() => {
setId(uuid())
}, [])
return <div>Hello Dialog</div>
}
Giving an empty array as the second parameter of useEffect makes it unable to trigger more than once.
But another extremely simple solution could be to just... create it outside of your component :
const id = uuid();
const Dialog = () => {
return <div>Hello Dialog</div>
}
You may store it in state:
const [id] = useState(uuid()); // uuid will be called in every render but only the first one will be used for initiation
// or using lazy initial state
const [id] = useState(() => uuid()); // uuid will only be called once for initiation
You may also store it in React ref:
const id = useRef(null);
if(!id.current) {
// initialise
id.current = uuid();
}
// To access it’s value
console.log(id.current);
Any instance property becomes a ref pretty much, and you would access idRef.current in this case for the id
function Dialog() {
const idRef = useRef(uuid())
return <div>Hello Dialog</div>
}
Thank you all, your solutions works well. I also try this solution and I find it OK too: replace this.id with Dialog.id. Is there any downside with this solution?

this.props Not Returning Fetched Data From Parent Component (React)

I am attempting to render playlist information for an Audio Player in React. The data is coming from a fetch call in the parent component (PostContent.js). The data being returned is an array of objects that looks like:
[ {name: ‘track name’, artist: ‘artist name’, url: ’https://blahblah.wav', lrc: ‘string’, theme: ‘another string’ }, {…}, {…}, etc. }
I am not able to return the data in the render() method of the child component (AudioPlayer.js). When I console.log(this.props.audio) in the render(), my terminal prints three responses. The first is an empty array, and the next two are the correct data that I need (an array of objects).
How can I set the props on the ‘audio’ key in the ‘props’ object in the render() method of the AudioPlayer.js component?
I should mention that I am using the react-aplayer library, and I am able to make this work with hard-coded data, as in the example here (https://github.com/MoePlayer/react-aplayer), but I am trying to make a dynamic playlist component for a blog website. Any advice is greatly appreciated.
AudioPlayer.js (Child Component)
import React, { PureComponent, Fragment } from 'react';
import ReactAplayer from '../react-aplayer';
import './AudioPlayer.css';
import sample from '../../src/adrian_trinkhaus.jpeg';
export default class AudioPlayer extends React.Component {
// event binding example
onPlay = () => {
console.log('on play');
};
onPause = () => {
console.log('on pause');
};
// example of access aplayer instance
onInit = ap => {
this.ap = ap;
};
render() {
console.log('props in render of AudioPlayer', this.props.audio)
const props = {
theme: '#F57F17',
lrcType: 3,
audio: this.props.audio
};
return (
<div>
<ReactAplayer
{...props}
onInit={this.onInit}
onPlay={this.onPlay}
onPause={this.onPause}
/>
</div>
);
}
}
PostContent.js (Parent Component)
import React, { Component, useState, Fragment } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import AudioPlayer from './AudioPlayer';
export default class PostContent extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
episodeData: [],
audio: []
}
}
async componentDidMount() {
const { id } = this.props.match.params;
const response = await fetch(`http://localhost:5000/episode/${id}/playlist`);
const jsonData = await response.json();
const songs = jsonData;
const audio = Object.keys(songs).map(key => {
return {
name: songs[key].name,
artist: songs[key].artist,
url: songs[key].url,
cover: songs[key].cover,
lrc: songs[key].lrc,
theme: songs[key].theme
}
});
this.setState({ audio })
}
componentDidUpdate(prevProps, prevState) {
if (prevState.audio !== this.state.audio) {
const newAudio = this.state.audio;
this.setState({ audio: newAudio }, () => console.log('new audio', this.state.audio))
}
}
render() {
return (
<Fragment>
<AudioPlayer audio={this.state.audio} />
<Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
{this.state.episodeData.map((item, i) => (
<div key={i} className="word-content">
<h2 className="show-title">{item.post_title}</h2>
<div className="episode-post-content">
<p>{item.post_content1}</p>
<p>{item.post_content2}</p>
<p>{item.post_content3}</p></div>
</div>
))}
<Table data={this.state.data} />
<div className="bottom-link">
<Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
</div>
</Fragment>
)
}
}
i played around with an async scenario with your code on codesandbox
i think the problem is when you're trying to access the payload in ReactAPlayer component when audio it's not loaded yet from the async call. what you need to do is only use "audio" when it's valid like this if (audio.length) {...} or audio && ... some form of check to prevent it from being accessed in the reactAplayer render function.
fyi - you can remove the componentDidUpdate hook, since you have a setState call inside the ...Didmount hook, when setState is called inside ...didMount, the component calls its render() thus trigger a child re-render and its child will do the same..
Actually I think it doesnt work because you set this.props inside a props obejct, so maybe you need to do something like
var that = this
const props = {
audio = that.props.audio
}

How to update state of a component through a button click in another component?

I have 2 components in my react application. On first time page load, the first component is supposed to make a query and display data(buttons) accordingly. The state of second component till now is empty. When the user clicks on any of the button, another request should be made to the sever and state of the second component should be changed and should be reflected on the web page.
These are my files..
Apps.js
import React, { Component } from 'react';
import './App.css';
import OrgList from "./orgList"
import OrgDetails from "./orgDetails"
class App extends Component {
render() {
return [
<OrgList/>,
<OrgDetails/>
];
}
}
export default App;
orgList.js
import React, { Component } from 'react'
import OrgDetails from "./orgDetails"
var posts =[]
class OrgList extends Component {
constructor(props){
super(props);
this.state={
mainpost: [],
devices:[],
}
}
componentDidMount(){
fetch(someURL)
.then(res => res.json())
.then(function (data){
for (let i = 0; i < 3; i++){
posts.push(data.orgs[i].name)
}
}).then(mainpost => this.setState({mainpost:posts}));
}
render() {
var token =new OrgDetails();
const postItems =this.state.mainpost.map((post) => (
console.log(post),
<button
data-tech={post}
key={post}
className="org-btn"
onClick={() => token.dispatchBtnAction(post)}
>
<h3>{post}</h3>
</button>
)
)
return (
<div>
<h3> Organisations!!!! </h3>
<h5>{postItems}</h5>
</div>
)
}
}
export default OrgList;
orgDetails.js
import React, { Component } from 'react'
var list =[]
const orgname = org =>
`someURL/${org}`
class OrgDetails extends Component {
state={
devices:[],
}
constructor(props){
super(props);
this.state={
devices: [],
}
this.dispatchBtnAction=this.dispatchBtnAction.bind(this)
}
dispatchBtnAction=(str) => {
list =[]
fetch(orgname(str))
.then(res => res.json())
.then(function (data){
for (let i = 0; i < 3; i++){
//console.log("123")
list.push(data.devices[i].location)
console.log(list)
}
}).then(devices => this.setState({
devices : list,
}));
}
render() {
const devices=this.state.devices.map((dev,i)=>(
<div key={dev}>
<li>{dev}</li>
</div>
))
return (
<div>
<p>{devices}</p>
</div>
)
}
}
export default OrgDetails;
But I am getting this warning...
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 OrgDetails component.
Because of this, the state is not getting changed and the component is not rerendering.
How to eliminate this warning and if any better method is there please do suggest.
As these 2 component are not parent-child components, perhaps you should implement all the logic in the App and than pass state-handlers as props to each component.
Then your components will look something like this:
class App extends Component {
state = { clicks: 0 }
incrementState = () {
const prev = this.state.clicks;
this.setState({ clicks: prev + 1 })
}
render() {
return [
<DisplayComponent counter={this.state.clicks} />,
<ControlComponent onIncrement={this.incrementState} />
];
}
}
Component that displays state
class DisplayComponent extends Component{
render() {
return (<h3>this.props.counter</h3>);
}
}
Component that handles state
class ControlComponent extends Component {
render() {
return (<button onClick={this.props.onIncrement}>click me</button>)
}
}
Well the whole issue is this line var token =new OrgDetails(); This just creates the object. But doesn't mount it in the DOM. It also doesn't reference to the component <OrgDetails/> created in App. So when you try to use token.dispatchBtnAction(post), you are trying to setState on a component that is not mounted in the DOM, hence the error.
This is a really questionable way of making communication in between two components. You are better off using a Parent-Child relationship in between component. Also you can have a look at making Presentational Component and Container components differentiation to make the workflow easy. Have a read at the this link.

Dynamically rendering react components from string array

Running into an issue rendering components dynamically as the come off the CMS in the react code.
Having no problem getting & parsing the variable names into an array to be utilized in the actual rendering - but receiving errors here no matter the method I'm using:
Warning: is using uppercase HTML. Always use lowercase
HTML tags in React.
Warning: is using uppercase HTML. Always use lowercase HTML tags in React.
Which clearly shows I'm using caps :)
import React, {
Component
} from 'react';
import {
createClient
} from 'contentful';
import CtaBlock from './CTABlock';
import DeviceList from './DeviceList';
class HomeContainer extends Component {
constructor(props) {
super(props);
this.state = {
pageCont: [],
entries: []
};
}
componentDidMount() {
const client = createClient({
// This is the space ID. A space is like a project folder in Contentful terms
space: '...',
// This is the access token for this space. Normally you get both ID and the token in the Contentful web app
accessToken: '...'
});
client.getEntries({
'sys.id': '5stYSyaM8gkiq0iOmsOyKQ'
}).then(response => {
this.setState({
mainCont: response
});
});
}
getEntries = pageCont => {
var linkedEntries = pageCont.includes.Entry;
console.log(linkedEntries);
return linkedEntries;
};
render() {
var formattedComponents = [];
var renderedComponents = [];
if (this.state.mainCont) {
//getting the type of component from the Contetful API (String)
var componentList = this.getEntries(this.state.mainCont).map(entries => entries.sys.contentType.sys.id);
//converting the component names to upper case
formattedComponents = componentList.map(comps => comps.charAt(0).toUpperCase() + comps.slice(1));
renderedComponents = formattedComponents.map(MyComponent => {
return <MyComponent / >
});
}
return (
<div>
<h1> Dynamically Generated Components Div </h1>
{renderedComponents}
</div>
);
}
}
export default HomeContainer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Appreciate any insight!
When I understand you right, what you want to archive is, to map a string key to a certain component, right?
So that entries.sys.contentType.sys.id contains a string like "ctaBlock"or "deviceList"?
I would suggest using a map as follows:
import CtaBlock from './CTABlock';
import DeviceList from './DeviceList';
import FallbackComponent from './FallbackComponent';
const keyMap = {
ctaBlock : CtaBlock,
deviceList : DeviceList,
default: FallbackComponent,
};
...
componentList.map( entries => {
const key = entries.sys.contentType.sys.id;
const Component = keyMap[ key ] || keyMap.default;
return <Component />;
} );
See an example on:
https://jsfiddle.net/v7do62hL/2/

Categories

Resources