react destructuring variable got undefined - reactjs

I am new to react. My problem is that my variables keep saying that it is undefined. What I am trying to do is to display those variable but fail to destructure it. A filter function is executed and return a single tour. The data is successfully retrieved. By destructuring this, some variable contains an array can not be displayed. Does anyone know how to fix this?
TypeError: Cannot read property '0' of undefined
My data looks like this.
[
{
"_id": "12345",
"name": "I am first tour",
"startLocation": {
description: "USA",
type: "point"
},
"startDates": [
"2021-06-19T09:00:00.000Z",
"2021-07-20T09:00:00.000Z",
],
"imageUrl": [
"https://something1.jpg",
"https://something2.jpg",
"https://something3.jpg",
],
},
//.....rest data
]
import React, { Component } from 'react';
import './Tour.css';
import { connect } from 'react-redux';
class Tour extends Component {
constructor(props) {
super(props)
this.findSingletour = this.findSingletour.bind(this);
}
findSingletour = (tourId) => {
const notYetFilterTours = this.props.tours.tourState.data;
let filtered = [];
if (notYetFilterTours) {
filtered = notYetFilterTours.find((tour) => {
if (tour.id === tourId) {
return filtered;
}
return filtered;
});
}
return filtered;
};
render() {
const tourId = this.props.match.params._id;
let SingleTour = this.findSingletour(tourId);
const {
name,
startLocation,
startDates,
imageUrl
} = SingleTour;
return (
<div>
<span>{name}</span> // successfully rendered
<span>{startLocation[0]}</span> // undefined
<span>{startDates[0]}</span> // undefined
<span>{imageUrl[0]}</span> // undefined
</div>
)
}
}
const mapStateToProps = (state) => ({
tours: state.tourContainer,
});
export default connect(
mapStateToProps,
)(Tour);

Need to do validation just in case:
class Tour extends Component {
// some code
render() {
const {
name,
startLocation,
startDates,
imageUrl
} = SingleTour;
return (
<div>
<span>{name}</span> // successfully rendered
<span>{startLocation && startLocation.length > 0 ? startLocation[0] : ''}</span> // undefined
<span>{startDates && startDates.length > 0 ? startDates[0] : ''}</span> // undefined
<span>{imageUrl && imageUrl.length > 0 ? imageUrl[0] : ''}</span> // undefined
</div>
)
}
}

You can provide default values, and it is generally a good idea to have sensible defaults in case data is not loaded and UI is rendered.
So something like this would prevent such errors:
const {
name = '',
startLocation = [],
startDates = [],
imageUrl = ''
} = SingleTour;
Now if your UI renders and tries to get 0 of startLocation, it won't fail. It will of course find nothing, and display nothing except the UI skeleton, but the app will not error out.

Related

react state updated undefined and render nothing

I'm still learning react. The data is retrieved from the redux action and store as props. My problem is that my variable is undefined after a filter function executed. What I am trying to do is using the data from redux action, and display those variable. The state of the component turn out to be undefined and nothing display on view. Does anyone know how to fix this?
https://i.stack.imgur.com/3xyJn.png
1) Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
2) Uncaught TypeError: Cannot destructure 'this.state.currentTour' as it is undefined.
[
{
"_id": "12345",
"name": "I am first tour",
"description": "Iasofisajdaiosjdioasdmoias",
"imageUrl": "https://something1.jpg",
"dates": [
"2021-06-19T09:00:00.000Z",
"2021-07-20T09:00:00.000Z",
],
},
{
"_id": "67890",
"name": "I am second tour",
"description": "cvxbcvbcxbcvbcxb",
"imageUrl": "https://something2.jpg",
"dates": [
"2023-01-12T09:00:00.000Z",
"2023-04-22T01:00:00.000Z",
],
},
//.....rest data
]
import React, { Component } from 'react';
import './Tour.css';
import { connect } from 'react-redux';
class Tour extends Component {
constructor(props) {
super(props)
this.state = {
currentTour: {},
}
this.findSingletour = this.findSingletour.bind(this);
}
componentDidUpdate() {
const tourId = this.props.match.params._id;
let FilteredTour = this.findSingletour(tourId);
// console.log(FilteredTour); ----> undefined
if (FilteredTour !== this.state.currentTour) {
this.setState({
currentTour: FilteredTour
});
}
}
findSingletour = (tourId) => {
const notYetFilterTours = this.props.tours.tourState.data;
let filtered = [];
if (notYetFilterTours) {
filtered = notYetFilterTours.find((tour) => {
if (tour.id === tourId) return true;
return filtered; // ---> actual object get back { id: '...' , name: '...', ..... }
});
}
};
render() {
const {
name,
description,
imageUrl,
dates,
} = this.state.currentTour || {}; // ---> undefined
return (
<div>
<span>{name}</span>
<span>{description}</span>
<span>{imageUrl}</span>
<span>{dates[0]}</span>
</div>
)
}
}
const mapStateToProps = (state) => ({
tours: state.tourContainer,
});
export default connect(
mapStateToProps,
)(Tour);
Try this, I don't know does it helpful or not, but it's work for me
For warning Can't perform a React state update...
=> to not see this warning add code below, and add if(!this.mounted) return; before where ever you use this.setState
private mounted = false as boolean;
componentWillUnmount() {
this.mounted = false
}
componentWillMount() {
this.mounted = true
}
I see your function findSingletour() should return default value for it.
Example:
findSingletour = (tourId) => {
const notYetFilterTours = this.props.tours.tourState.data;
let filtered = [];
if (notYetFilterTours) {
filtered = notYetFilterTours.find((tour) => {
if (tour.id === tourId) return true;
return filtered; // ---> actual object get back { id: '...' , name: '...', ..... }
});
}
return filtered; // or something else cause I saw you had return bool or filtered
// If you do not return here result maybe is undefined
};

How to initialise boolean variables in react?

i have a variable named data which is a array of objects as below,
data = [
{ attributes: [],
info: '',
meshes: [],
}
{attributes: [],
info: '',
meshes: [],
}
.....so on....
]
When the info is defined will display message info available..if info undefined will display message info unavailable.
So i do it like below within render function of the component
export default class DataInfo extends React.Purecomponent {
state = {
data: null,
};
componentdidMount() {
load_data();
}
load_data = () => {
/*send a request to server for fetching data and
set data state */
}
render = () => {
return (
{this.loading &&
<div className="spinner"/>}
{!this.data || (this.data && this.data.every((data.info) =>
!data.info)) &&
<div>No info available</div>}
{this.data && this.data.some((data.info) => data.info) &&
<div>info available</div>}
);
}
}
Now withing the conditionals rather than using the below statements,
this.data.every((data.info) => !data.info)
this.data.some((data.info) => data.info)
I want to have them defined as some explanatory variables...like has_some_info and has_no_info.
So to achieve it, within render function i tried using something like below,
const has_some_info = this.data ? this.data.some((data.info) =>
data.info): 'false';
const has_no_info = this.data ? this.data.every((data.info) =>
!data.info): 'false';
But this is not correct. it doesnt work fine..i don't want to initialise it to intialise variables to false....
Could someone help me to defined these variables....thanks.
In the first place, you should realize that every and some are the opposites and you don't have to calculate them both:
const infoAvailable = (this.state.data || []).some(data => data.info);
const noInfoAvailable = !infoAvailable;
In other words:
render() {
if (this.state.loading) {
return <div className="spinner"/>;
}
const infoAvailable = (this.state.data || []).some(data => data.info);
return infoAvailable
? <div>Info available</div>
: <div>No info available</div>;
}
(also note I have used this.state.data to access data).
export default class DataInfo extends React.Purecomponent {
state = {
data: null,
};
componentdidMount() {
load_data();
}
load_data = () => {
/*send a request to server for fetching data and
set data state */
}
render() {
const {loading, data = []} = this.state;
return (
{loading &&
<div className="spinner"/>}
{data.map(ele => ele.info
? <div>info available - {ele.info} </div>
: <div>No info available</div>
}
);
}
}
If you need self explanatory variables for info you could use !!ele.info which gives whether data is present or not.

How to properly get message count on form submission using reactjs

How to properly get message count on form submission using reactjs.
For hours now am on this trying to find the possible solution.
The Application below submits and displays message info and everything works fine.
Now I have task of implementing a message counter each time message is submitted by a user.
This is what I have done to implement counter for the user
var senderId ='Nancy101';
const {textCount} = this.state;
var count = textCount[senderId] == undefined ? 1 : textCount[senderId] + 1;
textCount[senderId] = count;
alert('am counting: ' +count);
Here is my issue after adding the textcount method above
Each time I submit the form am having error
Uncaught TypeError: Cannot read property 'Nancy101' of undefined
at bundle.js:109988
here is the line of code that causes the issue
var count = textCount[senderId] == undefined ? 1 : textCount[senderId] + 1;
Here is the code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
message: '',
};
this.sendMessage = this.sendMessage.bind(this);
}
componentDidMount() {
var textCount = [];
}
sendMessage = (message_text) => {
alert(message_text);
this.setState({
data: [
{ id: "1", name: "Nancy101", message: "Hello from User1"}
]
});
}
render() {
return (
<div>
<input type="text" placeholder="Message" value={this.state.message} onChange={ev => this.setState({message: ev.target.value})}/>
<br/>
<span onClick={ () => this.sendMessage(this.state.message)}>Submit</span>
{this.state.data.map((message, i) => {
if (message.message !=='' && message.name !=='') {
//var senderId=message.name;
var senderId ='Nancy101';
const {textCount} = this.state;
var count = textCount[senderId] == undefined ? 1 : textCount[senderId] + 1;
textCount[senderId] = count;
alert('am counting: ' +count);
return (
<div key={i}>
<div>
{message.name}: {message.message}
</div>
</div>
)
} else {
//alert nothing.
}
})}
</div>
);
}
}
The problem here is happening because you trying to get textCountfrom state. However, your state doesn't have a key named textCount.
This is what you are doing.
const { textCount } = this.state;
It's mean this.
const textCount = this.state.textCount;
Which is return you an undefined because your state object doesn't have that key.
Then you are trying to get the value of the key named Nancy101 from undefined object that's why you get that error.
You can fix it by add textCount in your initial state inside constructor like this.
constructor(props) {
super(props);
this.state = {
data: [],
message: '',
textCount: {},
};
Instead of get undefined here const {textCount} = this.state;, now you got an object. {}
Also, you can update this line.
`var count = textCount[senderId] == undefined ? 1 : textCount[senderId] + 1;`
To this.
`let count = !textCount[senderId] ? 1 : textCount[senderId] + 1;`
with this !textCount[senderId] it gonna check your data that is it equal 0, undefined or ''.

Prop I can access in component can't be rendered

My MERN app's purpose is to take a 3-digit input from a user and return the first prime number that contains those digits (ex: you enter 026, the app returns 10267). If my checker() function finds a match, I run updatePrimeNumber() to update that prime number's "match" variable to true. Database is updating properly.
I want to display all prime numbers that have "match" equal to true. I have a prop, primeNumbers, which contains all the primes I have entered into the database. I can access those numbers throughout my component, but I can not figure out how to render any of them, true or not. The error I receive is that primeNumbers is not defined.
import React, { Component } from 'react';
import gql from "graphql-tag";
import { graphql, compose } from 'react-apollo';
const PrimeNumbersQuery = gql`
{
primeNumbers {
id
text
match
}
}
`;
const UpdateMutuation = gql`
mutation($id: ID!, $match: Boolean!) {
updatePrimeNumber(id: $id, match: $match)
}
`;
class Prime extends Component {
checker = (primes) => {
let nums = this.props.checkedNumbersFromParent;
let recentChecked = (nums[nums.length - 1].text);
let recentCheckedRegExp = new RegExp(recentChecked);
for (var i in primes) {
let count = 0;
if (primes[i].text.search(recentCheckedRegExp) >= 0 && count < 1) {
this.updatePrimeNumber(primes[i]);
count = count + 1;
break;
}
}
return primes;
}
updatePrimeNumber = async (primeNumber) => {
await this.props.updatePrimeNumber({
variables: {
id: primeNumber.id,
match: primeNumber.match
},
update: store => {
const data = store.readQuery({ query: PrimeNumbersQuery });
data.primeNumbers = data.primeNumbers.map(
x =>
x.id === primeNumber.id
? {
...primeNumber, match: true
}
: x
);
store.writeQuery({ query: PrimeNumbersQuery, data });
}
});
};
render() {
const {data: {loading, primeNumbers}} = this.props;
this.checker(primeNumbers)
return (
<div>
***Need to render all primeNumbers with match === true***
</div>
);
}
}
export default compose(
graphql(UpdateMutuation, {name: 'updatePrimeNumber'}),
graphql(PrimeNumbersQuery)
)(Prime);
Thank you to anyone who looks at this. It is much appreciated.
About your problem:primeNumbers is not defined.UpdatePrimeNumber is async, you need to check it first and add constructor to initial this.props.
constructor(){
super(props)
}
renderprime(){
this.checker(this.props.data.primeNumbers)
if (this.props.data.primeNumbers){
return (
<div>
{this.props.data.primeNumbers.map((item) => {
if (item.match){
return (
<div>
<div>{item.id}</div>
<div>{item.text}</div>
</div>
)
}
})}
</div>
)
}
}
...
<div>
{this.renderprime()}
</div>
which line is the error being thrown from ?
You can try using the filter instead of updating the match in the primeNumber.
to render the prime numbers replace
Need to render all primeNumbers with match === true
loop through the primeNumbers

Graphql query result comes back undefined

I am getting the error Uncaught (in promise) TypeError: Cannot read property 'privateKey' of undefined
Employee query result comes back undefined when trying to console.log this.props.employee
I am using Graphql and Next.js. Am unsure whether or not componentWillMount is the correct lifecyle method to use as this.props.data.employee is undefined.
class EmployeeTable extends Component {
state = {
employeesList: [],
privateKey: ""
}
fetchEmployees = async () => {
console.log(this.props.data.employee);
console.log(this.props.data.employee.privateKey);
const adminWallet = new ethers.Wallet(this.state.privateKey, provider);
const EmployeeStore = new ethers.Contract(address, abi, adminWallet);
let count;
await EmployeeStore.functions.employeesCount().then(function(value) {
count = value;
});
let employeesList = [];
for(let i = 1; i<=count; i++) {
await EmployeeStore.getEmployeeByIndex(i).then(function(result) {
employeesList.push(result);
});
};
console.log(employeesList);
return {employeesList};
};
componentWillMount = async () => {
var employees = await this.fetchEmployees();
this.setState({employeesList: employees});
};
renderRows() {
return this.state.employeesList.map((employee, index) => {
return (<EmployeeRow
key={index}
employee={employee}
/>
);
});
};
render() {
const { Header, Row, HeaderCell, Body } = Table;
return(
<div>
<h3>Employees</h3>
<Table>
<Header>
<Row>
<HeaderCell>Name</HeaderCell>
<HeaderCell>Employee ID</HeaderCell>
<HeaderCell>Address</HeaderCell>
<HeaderCell>Authenticated</HeaderCell>
</Row>
</Header>
<Body>{this.renderRows()}</Body>
</Table>
</div>
)
}
}
const employee = gql`
query employee($employeeID: String){
employee(employeeID: $employeeID) {
privateKey
}
}
`;
export default graphql(employee, {
options: {
variables: {employeeID: "1234"}
},
})
(EmployeeTable);
The first time a component wrapped with a Query operation, like in your code, is rendered it receives the data prop but without the results yet.
data contains a field called loading. If it is set to true, it means the query didn't receive all the results from the server yet. If the operation is successful, next time your component is rendered this.props.data will have loading === false and this.props.data.employee should be have a value as you expect.
Basically, you should check if this.props.data.loading is true or false before calling fetchEmployees() and before rendering child components that rely on the results.

Resources