render data into an array using the map issues - javascript

im trying to render data into an array so that the data can be viewed in a chart in react native.
There seems to be an issue regarding maximum
import React, { Component } from 'react';
import { View,Button,Text } from 'react-native';
import { LineChart, XAxis, Grid } from 'react-native-svg-charts'
import n_data from './data'
class MyComponent extends Component {
constructor() {
super()
this.state = {data:[]}
}
render() {
const restructuredData = n_data.map( (name) => this.setState({data:name.volume}) )
return (
<View>
<Text> {this.state.data} </Text>
</View>
);
}
}
export default MyComponent;
my sample data is in n_data and looks like this
const n_data = [{"timestamp":"2011-08-18T00:00:00Z","volume":"5","spot_volume":"5","derivative_volume":"0"}]

Try formatting the data outside of the component (no need to use setState here) and then just set it as your inital state inside the constructor.
this.setState() usually triggers a render. When you call it directly from inside the render function there will probably be an endless loop.
The other thing is that your trying to render an array as Rohit already mentioned.

The error you are having because you are resetting state Ina render function which will try to re-render the component. You will need to modify your component, here is a quick example
import React, { Component } from 'react';
import { View,Button,Text } from 'react-native';
import { LineChart, XAxis, Grid } from 'react-native-svg-charts'
import n_data from './data'
class MyComponent extends Component {
constructor() {
super()
let data= null;
n_data.map(name=>{data=name.volume});
this.state = {data}
}
render() {
return (
<View>
<Text> {this.state.data} </Text>
</View>
);
}
}
export default MyComponent;

You can use the map function like this. Your restructuredData will eventually lead to a Maximum call depth error as the setState method is called multiple times and will cause the component to re-render equal to the length of your n_data array.
<View>
{n_data &&
n_data.map((item) => (
<Text key = {item.volume}>{item.volume}</Text>
))}
</View>
Also, you're trying to render an array as a Text component here
<Text> {this.state.data} </Text>
which is not correct.
Update:
This is how you can update the state
restructuredData = n_data => {
let updated_n_data = [];
// Object.values(objName) gives the values of an object
Object.values(n_data).map(item => {
updated_n_data = updated_n_data.concat(item.volume);
});
this.setState({
data: updated_n_data,
});
};

Related

ReactJS: Destructure Data in Class Component

So I have a file called Context.js which looks like the following:
const AppContext = createContext({
// ... scheme colour palette
color1: '#ADBDDB',
color2: '#7F8EB2',
color3: '#546287',
color4: '#384366',
// ... grey colour palette
grey1: '#FFFFFF',
grey7: '#2A3033',
// ... Nexus back-end constants
nexusIP: '126.0.0.2',
I want to import that file onto another component and use the "nexusIP" in that component. However, it is giving me issues. This is what I tried to do:
import Context from '../context/AppContext';
import React, { useContext, useState , Component } from 'react';
const { nexusIP, color5, grey1 } = useContext(AppContext);
class TempsAndTime extends React.Component {
constructor(props){
super(props);
this.state = {
bedTempDisplay: props.bedTemp,
bedTempUser: props.bedTemp,
hotEndTempDisplay: props.hotEndTemp,
hotEndTempUser: props.hotEndTemp,
pcBootTimeStamp: props.pcBootTimeStamp,
pcId: props.pcId,
hotEndTempCondition: null,
bedTempCondition: null
}
}
render() {
const { classes } = this.props;
let bedTempIcon;
let hotEndTempIcon;
return (
<div className={classes.container} >
<div className={classes.timeContainer} >
<Typography className={classes.timeElapsed}>
Time elapsed
</Typography>
</div>
<div>
);
}}
So I tried to destructure the value from that other Context.js file into this file but it was not letting me to do so. Any ideas?
according to React documentation you can't use hook inside a class component nor outside of a functional component. so, try with functional component and definitely call inside the component, otherwise consume the context as React suggest with render props

Does call to setState function in react native, only works in arrow function?

I need your help to explain about this react native code.
Below Code, when updateState function is written using arrow function, code is work perfectly
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Home extends Component {
state = {
myState: 'aaaaa'
}
updateState = () => {
this.setState({ myState: 'The state is updated' })
}
render() {
return (
<View>
<Text onPress = {this.updateState}>
UPDATE:{this.state.myState}
</Text>
</View>
);
}
}
but when I change the updateState function, using ordinary function (not arrow function) like code below, my state is not changed when text are pressed.
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Home extends Component {
state = {
myState: 'aaaaa'
}
updateState (){
this.setState({ myState: 'The state is updated' })
}
render() {
return (
<View>
<Text onPress = {this.updateState}>
UPDATE:{this.state.myState}
</Text>
</View>
);
}
}
My question is, does call to setState function must using arrow function?
Appreciate for your help about this matter.
Thank you
If you want to use without arrow should add bind in constructor()
class App extends Component {
constructor(props){
super(props);
this.state = {
myState: 'aaaaa'
}
this.updateState = this.updateState.bind(this);
}
updateState(){
this.setState({ myState: 'The state is updated' })
}
render() {
return (
<View>
<Text onPress = {this.updateState}>
UPDATE:{this.state.myState}
</Text>
</View>
);
}
}
If you want to use a function, you'd need to bind this in the constructor so that function updateState refers to the class when referring to this. Try the following:
constructor() {
this.updateState = this.updateState.bind(this);
}
Hopefully that helps!
On every render, reference to the function is created.
So, to avoid that, bind OR arrow function are used.
I call a function like this:
functionA = () => {}
TouchableOpacity onPress={()=> this.functionA()}

How to remove component that is rendered from a list? React Native

I've been following this tutorial for ReactJS and have been trying now to convert the simplistic Todo App (just checks off and on items) to React Native. I've been using expo to try it live on my phone and everything.
It all went good, but now I'm trying to add something. Whenever I click the checkbox I want to remove the component related to that item.
My idea was:
Since I'm rendering the TodoItem components from an array of todos,
and whenever I click a checkbox it updates the array as a whole
(looking for a certain id and updating it's completed variable). I can
run through the array and whenever the id is different I return the
todo. This way I returned every todo but the one with matching id to
be rendered.
import React, { Component } from 'react';
import { Alert,Image,StyleSheet, Text,Button, View } from 'react-native';
import TodoItem from './TodoItem'
import todosData from "./todosData"
export default class App extends React.Component {
constructor() {
super()
this.state = {
todos: todosData
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(id) {
this.setState(prevState => {
const updatedTodos = this.state.todos.map( todo => {
if(todo.id !== id) {
return todo
}
})
return {
todos:updatedTodos
}
})
}
render() {
const todoItems = this.state.todos.map( item =>
<TodoItem
key={item.id}
item={item}
handleChange = {this.handleChange}
/>
)
return (
<View style={styles.container}>
{todoItems}
</View>
);
}
}
This gives an error: ' TypeError:undefined is not an object (evaluating 'item.id')', giving at App.js:42:18
I'll also add the code referring to the TodoItem:
import React, { Component } from 'react';
import { Alert,Image,StyleSheet, Text,Button, View } from 'react-native';
import { CheckBox } from 'react-native-elements'
function TodoItem(props) {
return (
<View>
<CheckBox
checked={props.item.completed}
onPress={() => props.handleChange(props.item.id)}
/>
<Text>{props.item.text}</Text>
</View>
);
}
export default TodoItem
I don't understand why this won't work. It feels like I'm deleting the component while still using it (for it to give a undefined), but I don't see where. Since I'm simple updating a list of todos.
How can I do the thing I want?
PS: I seem unable to properly format the first segment of code. I apologize for that!
Try this:
handleChange(id) {
const { todos } = this.state
// filter out the deleted one
const filtered = todos.filter(x => x.id !== id)
this.setState({ todos: filtered })
}
We don't want to alter the state directly, but since .filter() creates a new array, without touching the given array, it is fine to use it. if it was another operation, you'd do something like this:
// create a copy
const newSomethings = [...this.state.somethings]
// do whatever with newSomethings
this.setState({ somethings: newSomethings })

How to render React components, stored in an array, inside the render method of another component

I've got a component, let's call Screen, which imports a component that will contain a search result. A method in Screen loops through an array of objects and for each object instaniates a new search result component and stores them in an array.
I'm new to React, so my question is, is it correct to create an instance of a class extending Component using the new keyword, or is there a proper React way to do this? If so what is the correct way of rendering these components in the Screen class, as the way I'm doing it in the snippet below doesn't seem to work as nothing renders.
Screen.js - I've cut down the file to just show what I'm on about
import React, { Component } from "react";
import { Text, View } from "react-native";
import SearchResult from "components/SearchResult";
class Screen extends Component {
searchResultsComponents = [];
submitSearchQuery(searchParam /* Array of objects */) {
this.searchResultsComponents = [];
for(let result in this.searchResults) {
this.searchResultsComponents.push(new SearchResult(this.searchResults[result]));
}
this.forceUpdate();
});
}
render() {
return(
<View>
{ this.searchResultsComponents.forEach((it) => { it.render(); }) }
</View>
);
}
}
export default Screen;
SearchResult.js
import React, { Component } from "react";
import { Text, View } from "react-native";
class SearchResult extends Component {
title;
setTitle(title) {
this.title = title;
}
getTitle() {
return this.title;
}
description;
setDescription(description) {
this.description = description;
}
getDescription() {
return this.description;
}
constructor(searchResult) {
super();
this.setTitle(searchResult.snippet.title);
this.setDescription(searchResult.snippet.description)
}
render() {
return(
<View>
<Text>{ this.title }</Text>
<Text>{ this.description }</Text>
</View>
);
}
}
export default SearchResult;
The proper way to approach this is, inside your render method:
{ this.searchResultsComponents.map((it, index) => <it key={index} />) }
The key is optional, but recommended by react to improve rendering performance when rendering an array of components.
See https://reactjs.org/docs/lists-and-keys.html#basic-list-component for more details.
Your approach does not work, because by just calling the render method, the HTML DOM is returned by the function call. However, you just call the function and don't do anything with the return value.
The reason your approach doesn't work is that forEach method doesn't return anything. Instead of forEach use map. Your modified line should look something like this:
this.searchResultsComponents.map((component, index) => <View key={index}>{component}</View>);
The reason I wrapped the component into View is because this way each item can get key attribute which is recommended when displaying arrays.

React Native - navigation issue "undefined is not an object (this.props.navigation.navigate)"

Im following this tutorial https://reactnavigation.org/docs/intro/ and im running into a bit of issues.
Im using the Expo Client app to render my app every time and not a simulator/emulator.
my code is seen down below.
I originally had the "SimpleApp" const defined above "ChatScreen" component but that gave me the following error:
Route 'Chat' should declare a screen. For example: ...etc
so I moved the decleration of SimpleApp to just above "AppRegistry" and that flagged a new error
Element type is invalid: expected string.....You likely forgot to export your component..etc
the tutorial did not add the key words "export default" to any component which I think it may have to do with the fact that im running it on the Expo app? so I added "export default" to "HomeScreen" and the error went away.
The new error that I cant seem to get rid off(based on the code below) is the following:
undefined is not an object (evaluating 'this.props.navigation.navigate')
I can't get rid of it unless I remove the "{}" around "const {navigate}" but that will break the navigation when I press on the button from the home screen
import React from 'react';
import {AppRegistry,Text,Button} from 'react-native';
import { StackNavigator } from 'react-navigation';
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends React.Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
Additional Info:
When you are nesting child components, you need to pass navigation as prop in parent component.
//parent.js
<childcomponent navigation={this.props.navigation}/>
And you can access navigation like this
//child.js
this.props.navigation.navigate('yourcomponent');
Reference: https://reactnavigation.org/docs/en/connecting-navigation-prop.html
With Expo you should't do the App registration your self instead you should let Expo do it, keeping in mind that you have to export default component always:
Also you need to import View and Button from react-native: please find below the full code:
import React from 'react';
import {
AppRegistry,
Text,
View,
Button
} from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat', { user: 'Lucy' })}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends React.Component {
// Nav options can be defined as a function of the screen's props:
static navigationOptions = ({ navigation }) => ({
title: `Chat with ${navigation.state.params.user}`,
});
render() {
// The screen's current route is passed in to `props.navigation.state`:
const { params } = this.props.navigation.state;
return (
<View>
<Text>Chat with {params.user}</Text>
</View>
);
}
}
const SimpleAppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen }
});
const AppNavigation = () => (
<SimpleAppNavigator />
);
export default class App extends React.Component {
render() {
return (
<AppNavigation/>
);
}
}
As Bobur has said in his answer, the navigation prop isn't passed to children of the routed component. To give your components access to navigation you can pass it as a prop to them, BUT there is a better way.
If you don't want to pass the navigation prop all the way down your component hierarchy, you can use useNavigation instead. (Which in my opinion is just cleaner anyways, and reduces the amount of code we have to write):
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Back"
onPress={() => {
navigation.goBack();
}}
/>
);
}
https://reactnavigation.org/docs/use-navigation/
This is just really nice because if you have multiple levels of components you wont have to continuously pass the navigation object as props just to use it. Passing navigation just once requires us to 1. Add a prop to the component we want to pass it to. 2. Pass the prop from the parent component. 3. Use the navigation prop to navigate. Sometimes we have to repeat steps 1 and 2 to pass the prop all the way down to the component that needs to use navigation. We can condense steps 1 and 2, no matter how many times they are repeated, into a single useNavigation call with this method.
I think it is best.
Try this Code: onPress={() => this.props.navigation.navigate('Chat')}
<ChildComponent navigation={props.navigation} {...data} />
This will make the navigation from the parent propagated to the subsequent child navigations.
const AppNavigation =()=>{ <SimpleApp />}
export default class App extends React.Componet{
render(){
return (
<AppNavigation/>
);
}
}

Categories