multiple this.setState(this.state) not re-rendering page - javascript

In my render, I have a function that updates the properties. I have listed the functions that get called between, but I think only the last one matters since it is the one that updates the data I use.
<button
onClick={() =>
this.handleUpdateProperty()
}>
Update Properties
</button>
which calls:
handleUpdateProperty = () => {
this.getDataBC();
this.setState(this.state);
//db.inventory.find( { status: "D" } )
}
That in turns calls:
getDataBC = () => {
var rentals = scFunctions.getRents();
console.log(web3.toAscii(rentals[1][0]));
for(let i = 0; i < rentals[0].length; i++){
let currentProp = {
status: rentals[0][i].toNumber(),
location: web3.toUtf8(rentals[1][i]).replace(/\s+/g,''),
company: web3.toUtf8(rentals[2][i]).replace(/\s+/g,''),
price: rentals[3][i].toNumber(),
start: rentals[4][i].toNumber(),
end: rentals[5][i].toNumber(),
help: "haha"
}
console.log(currentProp)
this.updateDB(currentProp);
}
this.getDataFromDb();
this.setState(this.state);
};
That in turn calls:
getDataFromDb = () => {
fetch("http://localhost:3001/api/property")
.then(property => property.json())
.then(res => this.setState({ data: res.data }))
.then(this.setState(this.state))
};
The last function does the:
`.then(res => this.setState({ data: res.data }))`
which updates the data I use to render my page. However, it doesn't update the page right away, I have to refresh the page to see the results from pressing the button. I thought
.then(res => this.setState({ data: res.data }))
would rerender the page?
Thank you so much
edit:
The constructor is as follows:
constructor(props) {
super(props);
this.state = {
data: [],
show: false, // show of the rental modal
company: "Homeaway",
id: 0,
message: null,
intervalIsSet: false,
idToDelete: null,
idToUpdate: null,
objectToUpdate: null,
rentProperty: "DongFang",
startDate: new Date(),
endDate: new Date(),
firstName: "Ludwig",
showConflict: true,
lastName: "Wittgenstein"
};
this.handleCompanySubmit = this.handleCompanySubmit.bind(this);
}
This is what uses the "data" from state. So I want this function to rerun and update the page when I setState...:
renderProperties = data => {
var properties = []
var propRow = []
data.forEach((property,index) => {
propRow.push(<Col xs={{ size:3, offset: .5}}>
<Jumbotron>
<Image src={require("./images/1.jpg")} fluid rounded />
<b> {property.location} </b>
<h1> Price: {property.price} </h1>
<div>
{this.renderStatusButton(property)}
</div>
</Jumbotron>
</Col>)
if((index+1)%3 == 0){ // if first in the row
properties.push(<Row>{ propRow }</Row>)
propRow = []
}
})
return (
<Container>
{properties}
</Container>
)
}
And this is in the render:
{this.renderProperties(data)}
I am going to bed. Thank you all for your help so far. If it doesn't get fixed, it is fine. It is not pivotal.

If I'm correct, you just want to refresh the page once the fetch in getDataFromDb() has finished, is that correct?
If so, you don't need all those setState() calls, you just need one in getDataFromDb(), which should be written as follow:
getDataFromDb = () => {
fetch("http://localhost:3001/api/property")
.then(property => property.json())
.then(res => this.setState({ data: res.data }))
};
That is, you don't need the last setState() call you wrote neither.
Anyways, in getDataBC() I see two functions (getRent() and updateDB) that I don't know what they do, so maybe there are some problems in those functions too.

Related

vuejs props are undefined after refresh

App.vue
template:
<ResponsiveNavigation
:nav-links="navLinks"
/>
script
data: () => ({
navLinks: []
}),
created: function() {
this.getSocialNetworks();
},
methods: {
getSocialNetworks() {
var self = this;
axios
.get(MY_API_URL)
.then(function(res) {
var fb_url = res.data.data.filter(obj => {
return obj.key === "Social_Facebook";
});
self.navLinks.fb = fb_url[0].defaultValue;
//
var ig_url = res.data.data.filter(obj => {
return obj.key === "Social_Instagram";
});
self.navLinks.ig = ig_url[0].defaultValue;
//
})
.catch(function(error) {
console.log("Error", error);
});
}
}
ResponsiveNavigation.vue:
<a :href="$props.navLinks.fb"></a>
if I console.log the $props.navLinks I have everything stored.
however in the href doesn't work after the FIRST load.
I am fairly sure that this is due to the reactive nature and UNreactive of arrays.
You're not really using an array, but an object
data: () => ({
navLinks: []
}),
to
data: () => ({
navLinks: {
fb:'',
ig:''}
}),
and I think it would setup the reactive props more suitably.
If you need an array, then use array.push() so it can react accordingly. I may also consider moving it to the mounted() method. Finally, you put $props in your code, do you have other props you've not shown us which may be conflicting?

MBDReact: How do I make a <datatable> row clickable?

I have setup my table in admin side of our application with MDBReact using the datatable. This table shows some small details of the stories that I have.
Now I have to make a row clickable i.e. add onClick to make a function call with the story id passed as an argument to this function.
Question:
How do I add onClick event to the datatable row?
(Below is my code.)
class Posts extends Component {
componentDidMount() {
this.getPosts();
}
getPosts = async () => {
const response = await fetch("http://****************/get_posts");
const post_items = await response.json();
this.setState({ posts: post_items.result }, () => {
console.log(this.state.posts);
this.setState({ tableRows: this.assemblePost() });
});
};
assemblePost = () => {
let posts = this.state.posts.map((post) => {
let mongoDate = post.dateAdded.toString();
let mainDate = JSON.stringify(new Date(mongoDate));
return {
postTitle: post.storyTitle,
// postDescription: post.storyDescription,
dateAdded: mainDate.slice(1, 11),
thankedBy: post.thankedBy.length,
reportedBy: post.reportedBy ? post.reportedBy.length : "",
userEmail: post.userEmail[0],
categoryName: post.categoryName[0],
};
});
console.log(posts);
return posts;
};
state = {
posts: [],
tableRows: [],
};
render() {
const data = {
columns: [
{
label: "Story Title",
field: "postTitle",
},
{ label: "Category Name", field: "categoryName" },
{
label: "User Email",
field: "userEmail",
},
{
label: "Date Added",
field: "dateAdded",
},
{
label: "Thanked",
field: "thankedBy",
},
{
label: "Reported",
field: "reportedBy",
},
],
rows: this.state.tableRows,
};
return (
<div className="MDBtable">
<p className="posts">Posts List</p>
<MDBDataTable striped bordered hover data={data} />
</div>
);
}
}
export default Posts;
To pull this off, here's what I did, but you'll need to appreciate these:
MDBDataTable requires you to manually define the columns and rows.
For data to render seamlessly, you define columns.field that correspond to rows[key]
Now, here's the logic, if you define a rows[key] that does not correspond to any columns.field, then that rows[key] is defined for an entire row just like we often pass index when working with map().
So based on the above observations,you can just pass the click event as a key/value pair to the row.And it will work just fine.
// ...
assemblePost = () => {
let posts = this.state.posts.map(
(post, i) => {
let mongoDate = post.dateAdded.toString();
let mainDate = JSON.stringify(new Date(mongoDate));
return {
index: i + 1, // advisable to pass a unique identifier per item/row
clickEvent: () => this.handleClick(storyId), // pass it a callback function
postTitle: post.storyTitle,
// ...others
categoryName: post.categoryName[0],
};
});
console.log(posts);
return posts;
};
// ...
Notice this clickEvent: () => this.handleClick(storyId), will be attached to the entire row.

How to push new data input to top on the list

hello how to push new data to the top list using vue.js and laravel, I tried but still failed, I hope someone can help with the problem.
this is my Controller
public function addComment()
{
$this->validate(request(), [
'comment' => 'required',
]);
$comment = [
'comment' => request()->comment,
'article_id' => request()->article_id,
'user_cid' => Auth::user()->user_cid,
];
$comment = ArticleComment::create($comment);
return new ArticleCommentResource($comment);
}
and this is my Vue.js Method
data() {
return {
data: [],
comments:[],
form: new Form({
comment: '',
article_id: this.articleid,
})
}
},
methods: {
onSubmit() {
this.showLoader = true
this.form.post('add-comment')
.then(response => {
console.log(response.article_id);
this.form.article_id = response.article_id;
});
},
}
how to handle it, thank you
I hope someone can help
Assuming your list simply loops through your comments array, you need to push the response at the first position of the list:
onSubmit() {
this.showLoader = true
this.form.post('add-comment')
.then(response => {
this.comments.unshift(response);
});
},
This assumes that response is the actual comment (I can't see into your form class).
<script>
import Form from 'form-backend-validation';
export default {
data:() => ({
form: new Form({
article_id: null,
}),
}),
mounted() {
this.fetch();
},
methods: {
async fetch() {
const response = await this.form.post('add-comment');
this.form.article_id = response.comment.article_id;
}
}
}
</script>
Please try this one.

Multiple Search Selection Dropdown

Tell me please, how can I set defaultValue in Multiple Search Selection Dropdown? I tried to set array of object like discribe in docs, but I do not receive what I want
constructor(props) {
super(props);
this.state = {
specs: [],
doctorSpecs: []
}
this.profileService = new ProfileService();
this.addSpecializationsService = new SpecializatoinsService();
}
componentWillMount() {
this.profileService.getProfileInformation()
.then((res) => {
this.setState({
profile: res.data,
consultationFees: res.data.consultation_fees,
mpdbRegistrationNumber: res.data.mpdb_registration_number,
qualification: res.data.qualification,
experienceYears: res.data.experience_years,
doctorSpecs: res.data.specializations.map((elem, index) => {
return {key: index, value: elem.id, text: elem.name}
})
})
})
this.addSpecializationsService.getSpecializationsList("", (res) => {
console.log(res);
this.setState({
specs: res.data.body.map((elem, index) => {
return {key: elem.id, value: elem.id, text: elem.name}
})
})
});
}
// other nessesary code
// component where must be this.state.doctorSpecs
<Dropdown
className='profile-specs'
placeholder='Skills'
fluid multiple selection search
options={this.state.specs}
onChange={this._onChangeSpecs}
value={this.state.doctorSpecs}
onSearchChange={this._getListSpecs}/>
I want , after render component, display array of values in this dropdown
I tried to use value, defaultValue, but it's not work
I find a problem.
I had to transfer to the array not objects, but text values from this objects

React setState only returning last item in a list saved to variable

I am very new to React, currently doing a small project of using GitHub API to return a search result via AJAX and be able to list that result on the screen. Currently I am using a for loop to iterate over the response data and saving that data to a variable, there is most likely a way better way to do this but like I said I am new. I then set the state to the returned data. The issue is in the setState it is only returning the last result saved to the variable and not the entire variable. Listed below is the entire component, any tips or advice would be greatly appreciated. Thank you!
import axios from 'axios';
import * as React from 'react';
class User extends React.Component<any, any> {
constructor(props: any) {
super(props);
this.state = {
name: name,
id: '',
userInput: '',
obj: null
};
}
handleSubmit(e: any) {
axios.get('https://api.github.com/users/' + this.state.userInput + '/repos')
.then((response) => {
if (response.data.length > 0) {
console.log('success');
let data1 = JSON.stringify(response.data);
let result = JSON.parse(data1);
for (let key in result) {
let obj = result[key];
let test = obj.name;
console.log(test);
this.setState({
name: name,
id: result[0].id,
obj: test,
userInput: this.state.userInput
})
};
} else {
console.log('else is working');
}
})
.catch((error) => {
console.log('error ');
});
}
render() {
return (
<div>
<form>
<input type="text" onChange={this.handleUserInput.bind(this)} value={this.state.userInput} />
<h1>{this.state.userInput}</h1>
<button type="button" onClick={this.handleSubmit.bind(this)}>Submit</button>
</form>
<h1>Name : {this.state.name}</h1>
<h1> ID : {this.state.id}</h1>
<h1>OBJ : {this.state.obj}</h1>
</div>
);
}
}
export default User;
The result from consoling the variable test gives this console output
console output
However when it is being set in obj by this.state.obj it is only showing the last item as shown here written to page
Every time you call setState, you overwrite the previous state. React tries to intelligently merge the provided (new) state and the previous state, but if there are any key collisions, the previous state (of that key) will be lost. If you want a list of items in your state, you'll have to do something like
let items = [];
for (...) {
items.push({
name: name,
id: result[0].id,
...
});
}
this.setState({ items: items });
following, you can access each item in the list by using this.state.items[someIndex] etc
Adding to #Tyler Sebastian answer,you can do this
let items = [];
for (let key in result) {
let obj = result[key];
let test = obj.name;
console.log(test);
items.push({
name: name,
id: result[0].id,
obj: test,
userInput: this.state.userInput
});
}
this.setState({ items: items });
and, the render section ,i think you can do this:
return (
<div>
<form>
<input type="text" onChange={this.handleUserInput.bind(this)} value={this.state.userInput} />
<h1>{this.state.userInput}</h1>
<button type="button" onClick={this.handleSubmit.bind(this)}>Submit</button>
</form>
{this.state.items.map((item) => {
<h1>Name : {item.name}</h1>
<h1> ID : {item.id}</h1>
<h1>OBJ : {item.obj}</h1>
})}
</div>
);
Thank you for your answers and tips I really appreciate it. What ended up happening is since I was calling setState within the for loop it was actually displaying all of the items but it was in a split second and would stop at the last so it seemed as if it was just showing the last. This is how I ended up fixing it.
handleSubmit(e: any) {
axios.get('https://api.github.com/users/' + this.state.userInput + '/repos')
.then((response) => {
if (response.data.length > 0) {
console.log('success');
let data1 = JSON.stringify(response.data);
let result = JSON.parse(data1);
let list = '';
for(let i of result) {
list += i.name + ' ';
}
console.log(list);
this.setState({
name: result[0].name,
id: result[0].id,
obj: list,
userInput: this.state.userInput
})
} else {
console.log('else is working');
}
})
.catch((error) => {
console.log('error ');
});
}
Definitely is not the best way to do this, but atleast it is working and I can work towards improving it. Thanks a lot for all the help!

Categories

Resources