update Axios Url with Onclick event in react - reactjs

I am working on an API using axios:
constructor(props) {
super(props);
this.state = {
url:[],
title:'anime',
limit:6,
}
this.more_button.bind(this)
}
componentDidMount() {
//limit is on the end of the url
const limit= this.state.limit
axios.get(`http://api.giphy.com/v1/gifs/search?q=sth&api_key=MY_KEY&limit=` + limit)
.then(res => {
const url= res.data.data;
this.setState({ url });
})
}
I want to change limit when i click on a button;
and i do it like this:
more_button=()=>{
this.setState((previousState) => {
return { limit: previousState.limit + 6 };
});
this.componentDidMount();
}
The problem is that i should click that button twice in order to work.
render part:
render(){
return(
<div className="container">
<button
onClick={this.more_button} >
Give me More!
</button>
)
}
}

ComponentDidMount is a lifecycle method. Don't call this function manually,Try below code.
componentDidMount() {
//limit is on the end of the url
this.apiCall();
}
apiCall() {
const limit= this.state.limit
axios.get(`http://api.giphy.com/v1/gifs/search?q=sth&api_key=MY_KEY&limit=` + limit)
.then(res => {
const url= res.data.data;
this.setState({ url });
})
}
more_button = () => {
this.setState((previousState) => {
return { limit: previousState.limit + 6 };
});
this.apiCall();
}
Change your render onClick method like:
onClick={()=>this.more_button}
Finally add extra line in constructor:
constructor(props) {
super(props);
this.state = {
url:[],
title:'anime',
limit:6,
}
this.apiCall = this.apiCall.bind(this);
this.more_button = this.more_button.bind(this);
}

Related

add data in this.state to use in another function

I'm trying to create a delete method in reactJS. My logic is to get the data from the api, use that data in the this.state and call it from the componentDidMount to delete the data.
I can't figure out how to make at the this.state to display the data ID or so I can delete it.
When I click Delete button I get the error of TypeError: Cannot read property 'state' of undefined
Anyone has an idea?
class DeleteForm extends Component {
constructor(props){
super(props);
this.state = {
id: ''
}
}
async componentWillMount() {
const url = 'http://localhost:8080/zoom';
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
componentDidMount() {
axios.delete(`http://localhost:8080/zoom/${this.state.id}`)
.then(res => console.log(res.data));
}
render() {
return(
<button onClick={this.componentDidMount}>Delete</button>
)
}
}
Assuming that you have id in the response. You can do it like this.
class DeleteForm extends Component {
constructor(props){
super(props);
this.state = {
id: ''
}
}
async componentDidMount() {
const url = 'http://localhost:8080/zoom';
const response = await fetch(url);
const data = await response.json();
this.setState({
id: data.id
})
}
delete = () => {
axios.delete(`http://localhost:8080/zoom/${this.state.id}`)
.then(res => console.log(res.data));
}
render() {
return(
{this.state.id && <button onClick={this.delete}>Delete</button>}
)
}
}
Your button will show up only when id is set.

Warning: Can't perform a React state update on an unmounted component....componentWillUnmount method

I'm very new to React and React Native and I am getting this warning when I switch screens. Also, the console.log keeps repeating infinitely, how do I fix it?
class DecodeScreen extends Component {
state = {
data: this.props.navigation.getParam("data", "NO-QR"),
bookData: '',
bookFound: false
}
bookSearch = () => {
query = `https://librarydb-19b20.firebaseio.com/books/${this.state.data}.json`,
axios.get(query)
.then((response) => {
const data = response.data ? response.data : false
console.log(data)
if (data) {
this.setState({
bookData: data,
bookFound: true
})
}
}).catch((error) => {
this.setState({
bookFound: false
})
})
}
renderContent = () => {
if (this.state.bookFound) {
return(
<View>
<TextH5>{this.state.bookData.title}</TextH5>
<TextH5>{this.state.bookData.author}</TextH5>
<TextH5>{this.state.bookData.publisher}</TextH5>
<TextH5>{this.state.bookData.isbn}</TextH5>
</View>
)
}
else {
return <TextH5>beer not found</TextH5>
}
}
componentDidMount() {
this.bookSearch()
}
render() {
{this.bookSearch()}
return (
<Container>
<TextH5>{this.state.data}</TextH5>
{this.renderContent()}
</Container>
);
}}
export default DecodeScreen;
the console.log outputthe warning
You can try this approach to see if it fixes the problem.
isMounted = false;
class DecodeScreen extends Component {
state = {
data: this.props.navigation.getParam("data", "NO-QR"),
bookData: "",
bookFound: false,
};
bookSearch = () => {
this.isMounted = true;
(query = `https://librarydb-19b20.firebaseio.com/books/${this.state.data}.json`),
axios
.get(query)
.then((response) => {
const data = response.data ? response.data : false;
console.log(data);
if (data) {
if (this.isMounted) {
this.setState({
bookData: data,
bookFound: true,
});
}
}
})
.catch((error) => {
this.setState({
bookFound: false,
});
});
};
renderContent = () => {
if (this.state.bookFound) {
return (
<View>
<TextH5>{this.state.bookData.title}</TextH5>
<TextH5>{this.state.bookData.author}</TextH5>
<TextH5>{this.state.bookData.publisher}</TextH5>
<TextH5>{this.state.bookData.isbn}</TextH5>
</View>
);
} else {
return <TextH5>beer not found</TextH5>;
}
};
componentDidMount() {
this.isMounted = true;
this.bookSearch();
}
componentWillUnmount() {
this.isMounted = false;
}
render() {
{
this.bookSearch();
}
return (
<Container>
<TextH5>{this.state.data}</TextH5>
{this.renderContent()}
</Container>
);
}
}
export default DecodeScreen;
You have to use componentDidMount method to do api call
componentDidMount() {
this.bookSearch()
}
Read about react life cycle method

Problems in passing parameters to custom middleware

Hi I am passing an id to the custom middleware I created in redux. here is my Dispatch function:
/** NPM Packages */
import React, { Component } from "react";
import { connect } from "react-redux";
import fetchCategory from "../../../actions/categoryAction";
import deleteCategory from "../../../actions/categoryDeleteAction";
/** Custom Packages */
import List from "../List";
//import API from "../../utils/api";
class Category extends Component {
constructor(props) {
super(props);
this.state = { categories: [], mesg: "", mesgType: "" };
this.onChange = this.onChange.bind(this);
}
/** Hook Call */
componentDidMount = async () => {
if (this.props.location.state)
this.setState({
mesg: this.props.location.state.mesg,
mesgType: this.props.location.state.mesgType
});
this.closeMesg();
this.props.fetchCategory();
};
/** Methods */
onChange = e => this.setState({ [e.target.name]: e.target.value });
onDelete = id => {
/*await API.delete("categories/" + id)
.then(res => {
const categories = this.state.categories.filter(el => el._id !== id);
this.setState({
categories: categories,
mesg: res.data.msg,
mesgType: "success"
});
})
.catch(err => console.log(err));
this.closeMesg();*/
this.props.deleteCategory(id);
};
closeMesg = () =>
setTimeout(
function() {
this.setState({ mesg: "", mesgType: "" });
}.bind(this),
30000
);
/** Rendering the Template */
render() {
const { mesg, mesgType } = this.state;
return (
<>
{mesg ? (
<div
className={"alert alert-" + mesgType + " text-white mb-3"}
role="alert"
>
{mesg}
</div>
) : (
""
)}
<List
listData={this.props.categories}
listName="category"
_handleDelete={this.onDelete.bind(this)}
/>
</>
);
}
}
const matchStatestoProps = state => {
return { categories: state.categories };
};
const dispatchStatestoProps = dispatch => {
return {
fetchCategory: () => dispatch(fetchCategory),
deleteCategory: (id) =>dispatch(deleteCategory(id))
};
};
export default connect(matchStatestoProps,dispatchStatestoProps)(Category);
Here is action:
import API from "../pages/utils/api";
const deleteCategory = (id,dispatch) =>{
API.delete("categories/" + id)
.then(() => {
dispatch({type:'DELETE'})
})
.catch(err => console.log(err));
}
export default deleteCategory;
here is my reducer:
const initState = [];
const categoryReducer = (state = initState, { type, payload }) => {
switch (type) {
case "FETCH_CATEGORY":
return payload.data;
case "DELETE":
alert("Data Deleted");
default:
return state;
}
};
export default categoryReducer;
Now i am getting this error :
Error: Actions must be plain objects. Use custom middleware for async actions.
▶ 6 stack frames were collapsed.
deleteCategory
src/app/pages/isolated/category/Categories.js:92
89 | const dispatchStatestoProps = dispatch => {
90 | return {
91 | fetchCategory: () => dispatch(fetchCategory),
> 92 | deleteCategory: (id) =>dispatch(deleteCategory(id))
93 | };
94 | };
95 |
If possible could someone say where am I going wrong?
Or is there any other way to pass parameters to the custom middleware?
Use redux-thunk as a middleware to handle async operations in Actions. Actions must be return plain objects, which means, something like below,
{
type : "DELETE",
payload : data
}
But in the Delete action you return a Promise, so that's why it is saying Actions must be return only plain objects. To handle this situation you can use a middleware like reduxt-thunk.
https://www.npmjs.com/package/redux-thunk
Edit -
If you use the Redux-thunk, In the catch bloack of the deleteCategory, you didn't return any object. You just console.log() the error. return the err from catch block and see if you see any errors with your API call
You can refer my react project
class Category extends Component {
constructor(props) {
super(props);
this.state = { categories: [], mesg: "", mesgType: "" };
this.onChange = this.onChange.bind(this);
}
/** Hook Call */
componentDidMount = async () => {
if (this.props.location.state)
this.setState({
mesg: this.props.location.state.mesg,
mesgType: this.props.location.state.mesgType
});
this.closeMesg();
this.props.dispatch(fetchCategory()); // we have to dispatch our action like
};
/** Methods */
onChange = e => this.setState({ [e.target.name]: e.target.value });
onDelete = id => {
this.props.dispatch(deleteCategory(id));
};
closeMesg = () =>
setTimeout(
function() {
this.setState({ mesg: "", mesgType: "" });
}.bind(this),
30000
);
/** Rendering the Template */
render() {
const { mesg, mesgType } = this.state;
return (
<>
{mesg ? (
<div
className={"alert alert-" + mesgType + " text-white mb-3"}
role="alert"
>
{mesg}
</div>
) : (
""
)}
<List
listData={this.props.categories}
listName="category"
_handleDelete={this.onDelete.bind(this)}
/>
</>
);
}
}
const matchStatestoProps = state => {
return { categories: state.categories };
};
export default connect(matchStatestoProps)(Category);
In your deleteCategory : you can access dispatch like
const deleteCategory = (id) => async (dispatch) =>{
await API.delete("categories/" + id)
.then(() => {
dispatch({type:'DELETE'})
})
.catch(err => console.log(err));
}
export default deleteCategory;

state becomes undefined after async call

Trying to understand why the component's state is becoming undefined.
Before the async call the console shows this.state.pubsubtopics as [], after the call it becomes undefined
code:
class PubSubTopics extends React.Component{
constructor(props){
super(props);
this.state = {
pubsubtopics: [],
};
}
componentDidMount() {
console.log('after component mounted');
console.log(this.state.pubsubtopics);
this.callBackEndAPI()
.then(res =>
this.setState({pubsubtopics: res.express}))
.catch(err => console.log(err));
console.log('after setting state');
console.log(this.state.pubsubtopics);
}
callBackEndAPI = async () => {
const response = await fetch('/listtopics');
const body = await response.json();
if(response.status !== 200){
throw Error(body.message)
}
return body;
}
handlePrintStateClick = () => {
console.log(this.state.pubsubtopics);
}
render(){
return(
<div>
<ul>
</ul>
<button onClick={this.handlePrintStateClick}>printState</button>
</div>
)
}
}
Logs (last log entry is from clicking the button):
after component mounted
index.js:16 []
index.js:21 after setting state
index.js:22 []
index.js:36 undefined
res.express didn't exist in the server's response, using res.topics solved the problem

How to increase axios speed?

Because I'm new to using axios so I usually have a trouble in using it. Specifically, I'm making a react-infinite-scroll feature now, but when I compare its speed with other site, my post(react-infinite-scroll feature) is gonna be shown slowly a little. Then I'm thinking this problem is caused by 2 reasons
1. I'm not using axios properly
2. There is a thing makes axios speed urgrade, but I'm not using it
Here's my code, please give me some advice to increase my http request speed.
Thank you for reading my question!
class MainPage extends Component {
constructor(props) {
super(props)
axios.get("http://127.0.0.1:8000/api/question")
.then(res => {
this.setState({
AnswerPostMultiList: res.data
})
}
)
.catch(err => {
console.log(err)
})
}
state = {
AnswerPostMultiList : []
}
componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener("scroll", this.handleScroll);
}
handleScroll = () => {
console.log("scroll is executing")
const { innerHeight } = window;
const { scrollHeight } = document.body;
const scrollTop =
(document.documentElement && document.documentElement.scrollTop) ||
document.body.scrollTop;
if (scrollHeight - innerHeight - scrollTop < 1000 && !this.props.isLoading["isLoading"]) {
this.props.onIsLoading() #To prevent this code from calling back continuously, change the value of this.props.isLoading["isLoading"] to false
axios.get("http://127.0.0.1:8000/api/question")
.then(res => {
this.setState({
AnswerPostMultiList: this.state.AnswerPostMultiList.concat(res.data)
})
this.props.onIsLoading() #change the value of this.props.isLoading["isLoading"] to true
}
)
.catch(err => {
console.log(err)
})
}
};
render() {
return(
<>
<PageHeader />
<div className="find_members">
{ this.state.AnswerPostMultiList.map((answerpost,index) => {
return <AnswerPostMulti question={answerpost.question_text} q_owner={answerpost.question_owner} answer={answerpost.answer_image} a_owner={answerpost.answer_owner} key={index} />
})
}
</div>
</>
)
}
}
const mapDispatchToProps = (dispatch) => ({
onIsLoading: () => {
dispatch(isLoadingActions.isLoading())
}
})
const mapStateToProps = state => ({
isLoading: state.isLoading
})
export default connect(mapStateToProps, mapDispatchToProps)(MainPage)
The best place to call a axios API calls is at componentDidMount(){}.
The Application loading process will be in this order skeleton->Initial rendering->later componentDidMount method is called. So here your app skeleton will be loaded and after that you can fetch data and use it to your app skeleton.
componentDidMount() {
axios.get("http://127.0.0.1:8000/api/question")
.then(res => {
this.setState({
AnswerPostMultiList: res.data
})
}
)
.catch(err => {
console.log(err)
});
}

Resources