props value come as undefined but print on browser console - reactjs

I have this strange issue, not sure what I am doing wrong. I pass a flags object to this components and it is available when I log it on console but it doesn't enter the loop observe logging Object.keys(flags) is undefined. Even when trying to access the value of an object directly, it is undefined.
class Home extends React.Component {
render() {
const allflags = [];
console.log('in Home component flags.. ', this.props.flags);
const {flags} = this.props;
console.log('Object.keys ', Object.keys(flags));
Object.keys(flags).forEach(key => {
console.log('key => ', key);
console.log('value => ', ''+ flags[key]);
allflags.push(<div>{key} : {''+ flags[key]}</div>);
});
console.log('Home Props flags', flags);
console.log('displayWallet >>>>>>>>> ', ''+flags['displayWallet']);
return (
<div>
<h1> All flags</h1>
{allflags}
</div>
);
}
}
Actual Result:
App.js:8 in Home component flags.. {}displayLogonStatus:true displayWallet: true __proto__: Object
App.js:10 Object.keys []length: 0__proto__: Array(0)
App.js:16 Home Props flags {}displayLogonStatus: false displayWallet: true __proto__: Object
App.js:17 displayWallet >>>>>>>>> undefined
Expected Result:
App.js:10 Object.keys []length: 0__proto__: Array(0) - Shouldn't be empty
App.js:17 displayWallet >>>>>>>>> undefined - Should be undefined when it is printed just above.

I think the problem you are having is how you are passing the props to the component.
I can suggest you to debug
console.log(this.props);
and check what is going on inside.
Also, I paste a working example of your code.
class Home extends React.Component {
render() {
const { flags } = this.props;
const allflags = [];
Object.keys(flags).forEach(key => {
allflags.push(<div>{key} : {''+ flags[key]}</div>);
});
return (
<div>
<h1>All flags</h1>
{allflags}
</div>
);
}
}
class App extends Component {
render() {
return (
<Home flags={{ displayLogonStatus: true, displayWallet: true }} />
);
}
}
I hope this helps you

Related

React - Class component doesn't receive any params

I have a simple class Component:
class SearchedUserWrapper extends Component {
constructor(props) {
super(props);
this.state = {
searchedPhrase: "",
pageNumber: 1
};
this.increment = this.increment.bind(this);
}
GetUserForSearchResult = (postAmount, pageNumber) => {
const list = [];
for (let index = 0; index < postAmount; index++) {
list.push(<SearchResultUser CurrentPage={pageNumber}></SearchResultUser>);
}
return list;
}
increment = () => {
this.setState({ pageNumber: this.state.pageNumber + 1 })
console.log(this.state.pageNumber + 0);
}
render() {
return (<div>
{this.GetUserForSearchResult(5, this.props.pageNumber)}
<Button onClick={this.increment}> Current page {this.state.pageNumber}</Button>
</div>);
}
}
and function GetUserForSearchResult receives a state from SearchUserWrapper class. My SearchResultUser looks like this:
class SearchResultUser extends Component {
render() {
{console.log(this.props.CurrentPage)}
return (
<div className="user-searchresult">
{this.props.CurrentPage}
</div>);
}
}
export default SearchResultUser;
And console log says that this props are undefined, and the div is empty.
My goal is to have the effect that everytime I click "Current page" button, to refresh all the SearchResultUser component so that it displays a state passed as parameter. What am I doing here wrong? Why does it says to be undefined?
EDIT:
I tried couple of things and discovered something.
If I send the state in the params directly, for example:
render() {
return (<div>
<SearchResultUser CurrentPage={this.state.pageNumber}></SearchResultUser>
</div>
It seems to work, but the order of sending the state to the function, which passes it to params of component doesn't work.
GetUserForSearchResult = (postAmount, pageNumber) => {
const list = [];
for (let index = 0; index < postAmount; index++) {
list.push(<SearchResultUser CurrentPage={pageNumber}></SearchResultUser>);
}
return list;
}
render() {
return (<div>
<SearchResultUser CurrentPage={this.state.pageNumber}></SearchResultUser>
</div>);
Can somebody explain why is it happening like this?
Edit:
In this place(below) I think you have to pass state instead of props, because the main component(SearchedUserWrapper) doesn't receive any props, so this is undefined.
{this.GetUserForSearchResult(5, this.props.pageNumber)}
https://codesandbox.io/s/stackoverflow-71594634-omvqpw
First message:
Did you check if the page number was updated?
If the next state depends on the current state, the doc of react recommend using the updater function form, instead:
this.setState((state) => {
return {quantity: state.quantity + 1};
});
You should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor at SearchResultUser

React SetState returns [Object Object] even though api returns valid json

Fetch is successful in below code (I have confirmed by looking at console - Network in browser) but the setState is not updating the allWeights array in state with the array of documents from MongoDB returned by API. When I use console.log() it prints what api returns but just setState is not working. I understand when render() executes allWeights array will have no value however after componentDidMount executes allWeights must have value if setState behaves as expected. I have searched for solutions provided for similar issue but they are not helpful for my issue. As the setState is not working the map function in render() throws error. Kindly help. I am stuck with this for last 3 days.
import React, {Component} from "react";
//
class TeamWeightsMain extends Component {
constructor(props) {
super(props);
this.state = {
allWeights: []
}
}
//
componentDidMount() {
console.log(`Entered componentDidMount()`);
fetch("http://localhost:8080/getallemployees")
.then(response => response.json())
.then((data) => {
this.setState(
{allWeights : data}
);
});
}
//
render() {
console.log(`Entered render() - allWeights value now : ${this.state.allWeights.toString() }`);
if(this.state.allWeights !== undefined && this.state.allWeights.length > 0) {
console.log(`this.state.allWeights.length: ${this.state.allWeights.length}`);
console.log(`this.state.allWeights: ${this.state.allWeights}`);
console.log(`this.state: ${this.state}`);
return(
<main>{
this.state.allWeights.map((emp,i) => {
return <div key={i}>
{emp.empName}
{emp.employeeWeights.map((weight,j) => {
return <div key={j} className="indentWeight">
Date: {new Date(weight.weighedOn).toLocaleDateString()}
{' '}
Weight: {weight.empWeight}
</div>
})}
</div>}
)
}
</main>)
}
else {
console.log(`Inside Not authorized : ${this.state.allWeights}`);
return (
<main>
<h2>Teamweights</h2>
<div className="indentWeights">
Sample text
</div>
</main>
)
}
}
}
//
export default TeamWeightsMain;

Cannot read property 'id' of undefined when creating a todo in NewTodo.jsx

I'm trying to create a new todo and pass todo is creating id to redirect component but I've got following issue: "Cannot read property 'id' of undefined". This is NewTodo.jsx, when It's the error:
class NewTodo extends Component {
state = {
redirect: false
};
componentDidMount() {
this.props.newTodo();
}
submit = todo => {
return this.props
.saveTodo(todo)
.then(response => this.setState({ redirect: true }))
.catch(err => {
throw new SubmissionError(this.props.errors);
});
};
render() {
return (
<div>
<h2>New Todo</h2>
{this.state.redirect ? (
<Redirect to={
//ERROR {pathname:`/todos/${this.props.location.state.id}/watch`,
//ERROR state: {id: this.props.todo._id}}
}
/>
) : (
<TodoForm todo={this.props.todo} onSubmit={this.submit} />
)}
</div>
);
}
}
function mapStateToProps(state) {
return {
todo: state.todosDs.todo,
errors: state.todosDs.errors
};
}
export default connect(
mapStateToProps,
{ newTodo, saveTodo }
)(NewTodo);
At lines when say ERROR it seems I'm passing an undefined id value. How can I access todo id I'm creating just the moment?
The expect result is '/todos/8eqwnhwebewj/watch' but real output is this following issue:
Cannot read property 'id' of undefined
Looks like you are not wiring up the id with the correct object:
it should be it it a query param this.props.location.search.id not this.props.location.state.id
it should be it it a param eg /path/:id -> this.props.location.match..id not this.props.location.state.id
<Redirect to={`/todos/${this.props.todo._id}/watch`} }
/>
) : (
<TodoForm todo={this.props.todo} onSubmit={this.submit} />
In your case you need to redirect to the path like this:
/todos/${this.props.todo._id}/watch
if you using react-router-dom and this is not a component that renders directly in a route, try using withRouter to get the history, location and match as props in your component.
withRouter would provide react-router-dom props into your component.
api here

Accessing nested json in React

I can successfully fetch json object from the api. However there seems to be a problem in updating the state.
After printing the object I get expected and desired result console.log(videos2.list[0]); gives 1st item from the list attribute of json object, you can check how the api looks under this link:
https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars
However when updating state with setState property selectedVideo: videos.list[0] is undefined.
The code for the component:
class App extends Component {
constructor(props) {
super(props)
this.state = {
videos2:[],
selectedVideo:null
}
this.DMSearch()
}
DMSearch(){
fetch(`https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars`)
.then(result => result.json())
.then(videos2 => {
console.log(videos2.list[0]);
this.setState({
videos2: videos2.list,
selectedVideo: videos2.list[0]
});
console.log(selectedVideo);
});
}
render () {
const DMSearch = this.DMSearch()
return (
<div>
<SearchBar onSearchTermChange= {DMSearch}/>
<VideoDetail video={this.state.selectedVideo}/>
<VideoList
onVideoSelect={selectedVideo=>this.setState({selectedVideo})}
videos2={this.state.videos2}/>
</div>
)
}
}
And exact error is Uncaught (in promise) ReferenceError: selectedVideo is not defined
videos2:list[0] produces correct results, but when assigned to selectedVideo it is undefined
As requested I am also including the code for vide_list which uses the objects form parent component which might be producing error here:
const VideoList = (props) => {
const videoItems = props.videos.map((video)=>{
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video={video} />
)
})
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
)
}
To be specific, this line
const videoItems = props.videos.map((video)=> {
causes the error when reading props. I believe this has something to do with selectedVideo being null...
There is an issue at this line
console.log(selectedVideo);
You printed out an undefined variable. It should be this.state.selectedVideo.
The error selectedVideo is not defined happens because selectedVideo is not a variable, it is a key on the javascript object passed to this.setState function.
//...
this.setState({
videos2: videos2.list,
selectedVideo: videos2.list[0]
});
//...
You can mitigate the error by creating a variable:
DMSearch(){
fetch(`https://api.dailymotion.com/videos?fields=description,id,thumbnail_url,title,&limit=5&search=cars`)
.then(result => result.json())
.then(videos2 => {
console.log(videos2.list[0]);
const selectedVideo = videos2.list[0]; // create variable
this.setState({
videos2: videos2.list,
selectedVideo: selectedVideo
});
console.log(selectedVideo);
});
}

Redux/React: why `this.props` undefined

My codes:
render() {
console.log( 'render, state' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
return (
<section>
<div>testing</div>
<div>{JSON.stringify(this.props.users)}</div>
<ul>
{this.props.users.map( user => <li>{user.email}</li>)}
</ul>
</section>
);
}
Both <div>testing</div> and <div>{JSON.stringify(this.props.users)}</div> work fine (after removing <ul>...</ul>). But <ul>...</ul> did not work. the error is:
Uncaught TypeError: Cannot read property 'map' of undefined
Any comments welcomed. Thanks
UPDATE
The following codes work fine, this.props.users is an Array, and all the console logs look OK. I just need to know why <ul>{this.props.users.map( user => <li>{user.email}</li>)}</ul> not work. Why this.props.users in <ul>...</ul> is undefined.
render() {
console.log( 'render, state' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
return (
<section>
<div>testing</div>
<div>{JSON.stringify(this.props.users)}</div>
</section>
);
}
the console output of the above codes (only two s):
render, statetrue,[{"_id":"5831e6df511e","updatedAt":"removed","createdAt":"removed","email":"removed","password":"xxxx","__v":0,"role":"xxx","profile":{"firstName":"test","lastName":"tester"}},{...}, {...}]
UPDATE
My codes:
import { connect } from 'react-redux';
import { fetchAllUsers } from '../../actions/index';
class HomePage extends Component {
componentWillMount() {
console.log( 'componentWillMount()' );
this.props.fetchAllUsers();
}
render() {
console.log( 'render(), ' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
return (
<section>
<div>{JSON.stringify(this.props.users)}</div>
</section>
);
}
}
function mapStateToProps(state) {
console.log( 'state:' + JSON.stringify(state) );// working fine, and the console.log is OK. not added to this post
return {
users: state.admin.users
}
}
export default connect(mapStateToProps, {fetchAllUsers})(HomePage);
console.log (some details in the User objects removed.):
render(), true,[{"_id":"5831","profile":{"firstName":"test","lastName":"tester"}},{"_id":"5831e874cedf511f", "profile":{"firstName":"cccc","lastName":"cc"}},{"_id":"5831120","profile":{"firstName":"cccccccc","lastName":"ccc"}}]
And, on the webpage, the string of this.props.users is shown.
My question is why <ul>{this.props.users.map( user => <li>{user.email}</li>)}</ul> not work, but <div>{JSON.stringify(this.props.users)}</div> working fine.
I think I already described my questions clearly. If more information needed, please tell me.
More details
my admin_reducer.js
import { FETCH_ALL_USERS } from '../actions/types';
const INITIAL_STATE = { users:[] };
export default function (state = INITIAL_STATE, action) {
console.log( 'users is action.payload:'+JSON.stringify( { users:action.payload } ) );
return Object.assign( {}, state, {users:action.payload});
//return { ...state, users:action.payload };
}
my index.js
import adminReducer from './admin_reducer';
const rootReducer = combineReducers({
...
admin: adminReducer
});
export default rootReducer;
my action.js
export function fetchAllUsers() {
return function(dispatch) {
axios.get(`${API_URL}/user/all`)
.then(response => {
dispatch({
type: FETCH_ALL_USERS,
payload: response.data
});
})
.catch(response => dispatch(errorHandler(response.data.error)))
}
}
UPDATE
why console log of console.log(this.props.users) is [object Object],[object Object],[object Object]?
First of, according to react docs, async requests should be made inside the componentDidMount method.
Secondly, to make sure that you're not trying to map an un-initialized array, use this:
<ul>{(this.props.users || []).map( user => <li>{user.someProperty}</li> )}</ul>
This should cover it in case you forgot to initialize the array for some reason.
You can call this without error..
JSON.stringify(this.props.users)
...because it just outputs "undefined"). That is valid. However, if you try to call a method on the undefined that was returned, of course that fails...
// Following tries to call undefined.map(), which is of course wrong
this.props.users.map( user => <li>{user.email}</li>)
Common shorthand to address your scenario uses a "short-circuit operator" (like a quickie "if (is true)")...
<ul>{this.props.user && this.props.users.map( user => <li>{user.email}</li>)}</ul>
^^ Note the "this.props.user && ", which prevents the following this.props.user.map() from being called if this.props.user is null or undefined

Resources