this.state.names.map is not a function - javascript

This is my code I just need to fetch data from the API and want to map it but I cannot do it I don't know why. I have gone though all the video tutorials but still couldn't find my problem.
class App extends Component {
state = {
names: [],
isLoaded: false,
}
constructor(props) {
super(props);
}
componentDidMount() {
fetch("https://dog.ceo/api/breeds/list/all")
.then(res => res.json())
.then(name => {
this.setState({
names: name,
isLoaded: true,
})
});
}
renderNames() {
if(this.state.names.length > 0) {
return this.state.names.map((breed) =>
<div key={breed.message}>
{breed.message}
{breed.status}
</div>
)
}
else{
return;
render(){
this isloaded is also an issue every time I find a way this states ruins everything
if (!this.state.isLoaded) {
return <div>loading....</div>
}
else{
return (
<div className="App">
<h1>Choose a name of breed</h1>
{this.renderNames()}
</div>

Bind this to renderNames in constructor.
like:
constructor(props) {
super(props);
this.renderNames = this.renderNames.bind(this)
}
OR
Re-write renderNames as a arrow function.
e.g.
renderNames = () => {
//Your code.
}

First things first... Re-arrange your code.. Place your state within constructor.. Then... Console.log your name value from the promise and see if the data is actually present... Then we will know what next to do.

Related

Having trouble invoking method in child that is passed as prop from parent

I have found a bunch of questions that seem like duplicates but I cannot seem to fix this issue I am having. I have a parent component:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
//some other props
currentDate: moment()
};
componentDidMount() {
this.fetchData();
}
fetchData() {
this.setState({
//set some state here
});
//Some Api call
}
onDateChange(currentDate) {
this.setState({
currentDate
});
}
//doing some stuff to render a table
return (
<div>
<ChildComponent
currentDate={this.state.currentDate}
onDateChange={(date) => this.onDateChange(date)}
/>
{currentView}
</div>
);
}
render() {
return (
<div>
//renders table
</div>
);
I am able to pass the method onDateChange to the child. And the child looks like:
class Child extends Component {
constructor(props) {
super(props);
this.state = {
currentDate: this.props.currentDate,
focused: false
};
render() {
return (
<div className="form-group">
<SingleDatePicker
date={this.state.currentDate}
onDateChange={(date) => this.props.onDateChange(date)}
focused={this.state.focused}
onFocusChange={({ focused }) => this.setState({ focused: focused })}
/>
</div>
);
For whatever reason I am unable to invoke the onDateChange method. If I console.log(this.props) I can see that the function is being passed as a prop. If I console.log(this.props.onDateChange) it returns:
ƒ onDateChange(currentDate) {
this.setState({
currentDate: currentDate
});
}
I can see the function and the code its supposed to execute. I have tried creating a method that calls this.props.onDateChange and then calling that method but it still does not work. I am confused as to why I am able to get the method to pass as a prop but I cannot invoke it. I realize there are a lot of questions asking how to pass function as a prop (I am able to do this) I just can't get this function to execute. Thanks in advance.
EDIT: I have updated the code to add the suggestions below. I am now getting no errors but It is still not working as expected. I will report back if/when i figure it out.
You forgot to invoke the function inside the arrow function:
onDateChange={(date) => this.props.onDateChange(date)}
Could you share the complete file, including the import classes and the export as well?
From this part of the code shared, some issues that I can see:
The constructors of both classes are missing a closing bracket;
The return in Parent (//doing some stuff to render a table) is misplaced. Did you want to put that inside the render method?
Maybe something like this?
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
//some other props
currentDate: moment()
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
this.setState({
//set some state here
});
//Some Api call
}
onDateChange(currentDate) {
this.setState({
currentDate
});
}
render() {
//doing some stuff to render a table
return (
<>
<div>
<ChildComponent
currentDate={this.state.currentDate}
onDateChange={this.onDateChange.bind(this)}
/>
{currentView}
</div>
<div>
{/* renders table */}
</div>
</>
);
}
}
There are still missing pieces in here like this currentView, so, if you could give more context, it would be great.
I hope it helps.
To pass the method to the child, remove the .bind(this):
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
//some other props
currentDate: moment()
};
componentDidMount() {
this.fetchData();
}
fetchData() {
this.setState({
//set some state here
});
//Some Api call
}
onDateChange(currentDate) {
this.setState({
currentDate
});
}
//doing some stuff to render a table
return (
<div>
<ChildComponent
currentDate={this.state.currentDate}
// Removed .bind(this)
// added missing parameter
onDateChange={(date) => this.onDateChange(date)}
/>
{currentView}
</div>
);
}
render() {
return (
<div>
//renders table
</div>
);

React don't change state after first method trigger

In my React app i have components structure:
-AllElements
--SingleElement
--SingleElementDetails
I am passing method See to SingleElement component where I invoke seefunc to invoke see method from AllElements component. The problem i my state (name) in AllElements not change after first onClick trigger, it changes after secund click. Could you tell my why ?
class AllElements extends Component {
constructor(props) {
super(props);
this.state = {
myData: [],
viewingElement: {
name:""
}
}
this.see = this.see.bind(this);
console.log('Initial Sate',this.state.viewingElement);
}
see(name) {
this.setState({
viewingElement: {
name:name
}
});
console.log('State after SEE',this.state.viewingElement);
}
render() {
const { myData, viewingElement } = this.state;
return (
<div>
{myData.map(se => (
<SingleElement
key={se.id}
name={se.name}
see={this.see}
/>
))}
<SingleElementDetails viewingElement={viewingElement}/>
</div>
);
}
}
class SingleElement extends Component {
constructor(props) {
super(props);
}
seefunc(name) {
this.props.see(this.props.name);
console.log('Name in seefunc props',this.props.name);
}
render() {
return (
<div onClick={this.seefunc.bind(this)}>
DIV CONTENT
</div>
)
}
}
The problem you have here is that setState is asynchronous. It does work the first time but you do not see it in your console.log because the console.log happens before the state is updated.
To see the updated state use the second argument of setState which is a callback function (https://reactjs.org/docs/react-component.html#setstate):
this.setState({
viewingElement: {
name:name
}
}, () => {
console.log('State after SEE',this.state.viewingElement);
});
And in SingleElement use the componentWillReceiveProps(nextprops) (https://reactjs.org/docs/react-component.html#componentwillreceiveprops) method from react lifecycle to see the updated props:
seefunc(name) {
this.props.see(this.props.name);
}
componentWillReceiveProps(nextprops) {
console.log('Name in props',nextProps.name);
}
It does change. However setState is an aync process so you're only logging the previous state to the console. setState does provide a callback that allows you to run code after the async process has finished, so you can do:
this.setState({
viewingElement: {
name:name
}
}, () => console.log('State after SEE',this.state.viewingElement));
DEMO

using getOffsetHeight with async data after render in react

Below code is simple, but it's ok impropriate in my opinion. Basically I try to calculate the height of a list. But what's a better solution than doing a setTimeout hack? I tried componentDidMount, but that doesn't guarantee the data is loaded.
class App extends Component {
constructor() {
super();
this.state = {
users: null
};
}
componentWillMount() {
axios.get("https://randomapi.com/api/6de6abfedb24f889e0b5f675edc50deb?fmt=raw&sole")
.then(response => this.setState({ users: response.data }));
}
componentDidMount() {
setTimeout(() => {
console.log(this.userElem.offsetHeight);
}, 1000);
}
render() {
return (
<div style={styles}>
<div ref={elem => (this.userElem = elem)}>
{this.state.users &&
this.state.users.map(o =>
<p>
{o.first}
</p>
)}
</div>
</div>
);
}
}
demo https://codesandbox.io/s/j46o2656vy
Instead of making the api call inside componentWillMount do it inside componentDidMount method, and use setState callback method to check the element height.
Like this:
componentDidMount() {
axios.get("https://randomapi.com/api/6de6abfedb24f889e0b5f675edc50deb?fmt=raw&sole")
.then(response => {
this.setState({ users: response.data }, () => {
console.log(this.userElem.offsetHeight);
})
});
}
Or you can also use componentDidUpdate method, it is invoked immediately after updating occurs. This method is not called for the initial render.
You could use componentDidUpdate and check your this.userElem.offsetHeight variable there.Also, i'd change componentWillMount with componentDidMount. You can read more here.

what to do with response object in react js

i'm working with react to complete the front end of a rest application.
I have json being sent to the front end, and I use fetch .
fetch('/task')
.then(function(data) {
return data.json();
})
.then(function(json) {
json.tasks.forEach(function(task) {
console.log(task.name)
})
});
So i'm able to console.log each task.name, but where to now? How do I get my component to display each task as a ?
Basically, where in a component does this type of logic go? Do i save the fetch request to a variable and then setState = variable?
this is my component:
class Task extends React.Component {
render() {
return <p> hey </p>
}
}
You need to initialize a state object, which you can update when the fetch is complete:
class Task extends React.Component {
constructor () {
super()
this.state {
tasks: null
}
}
componentDidMount () {
fetch('/task')
.then((data) => {
return data.json()
})
.then((json) => {
this.setState({ tasks: json.tasks })
})
}
renderTaskList () {
if (this.state.tasks) {
return (
<ul>
{this.state.tasks.map((task, i) => <li key={i}>{task.name}</li>)}
</ul>
)
}
return <p>Loading tasks...</p>
}
render () {
return (
<div>
<h1>Tasks</h1>
{this.renderTaskList()}
</div>
)
}
}
Edit: Re-reading this answer, I just wanted to note that it is not necessary to initialize the tasks property of the state object in this case. You could also just do something like:
this.state = {}
However, I think there is some value in explicitly naming the various properties of your state object, even if they are initialized as null. This allows you to write components whose state is documented in the constructor, and will prevent you or your teammates from later guessing how a component's state is modeled.

Update state when view loads

First time working with React, I need to know how to update the state when the view loads.
All I am trying to do is a GET request in order to get a list of dealers for a Casino Game. Basically, I am missing 1 or 2 steps which are for render the dealers's list in the DOM
I will show what I am doing with my code and after that I will explain what I want
here is the first step in the actions part
getDealerActions.js
class GetDealersActions {
constructor () {
this.generateActions('dealerDataSuccess', 'dealerDataFail');
}
getDealers (data) {
const that = this;
that.dispatch();
axios.get('someroute/get-dealers/get-dealers')
.then(function success (response) {
that.actions.dealerDataSuccess({...response.data});
})
}
};
then we move to the stores
getDealersStore.js
class GetDealersStore {
constructor () {
this.state = {
dealerData : null,
};
}
#bind(GetDealersActions.dealerDataSuccess)
dealerDataSuccess (data) {
this.setState({
dealerData : data,
});
console.log(this.state.dealerData);
}
}
in this case that console.log(this.state.dealerData); returns something like this which is exactly what I need
Object {dealersData: Array[3]}
the problems comes in the component part, honestly because I don't know how to handle the data there
class Dealers extends Component {
constructor (props) {
super(props);
}
static getStores () {
return [ GetDealersStore ];
}
static getPropsFromStores () {
return GetDealersStore.getState();
}
render () {
// here need to implement the .map function but
// as this.props.dealerData is null, I am unable to render it.
return (
<div>
<ActionButton onClick={this._getDealers}>Test</ActionButton>
//in some part here I need to render the list of dealers
</div>
);
}
_getDealers = () => {
console.log(this.props.dealerData);
GetDealersActions.getDealers();
}
}
this console.log(this.props.dealerData); returns null the first time, I have to click twice on _getDealers() in order to get this
{params: Object, query: Object, dealerData: Object}
so, what should I do in the render method in order to get dealerData filled out? and what should I do to update the state once I am in the view ?
If you got it, all I need is to get this.props.dealerData with data and not null. So I can render it in this view.
The way this should be structured is:
class Dealers extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
GetDealersActions.getDealers();
}
render() {
let content;
if (this.state.dealerData) {
content = this.state.dealerData.map((datum) => {
return <div>TODO: JSX!</div>;
);
} else {
content = <div>Loading . . .</div>;
}
return <div>{content}</div>;
}
}

Categories