How to use state parameter in fetch url correctly? - reactjs

Hello I have problem to set state variable in url parameter. I have tried few example I found in internet, but no one works for me.
I tried this:
constructor(props) {
super(props);
this.state = {
channelId: []
};
}
componentDidMount() {
this.setState({ channelId: '1ae2275e-2ca2-42cb-be13-e97b59fbae13' });
}
componentWillMount() {
fetch(
`http://localhost:8080/api/channel/${this.state.channelId}`)
.then...
And this:
constructor(props) {
super(props);
this.state = {
channelId: []
};
componentDidMount() {
this.setState({ channelId: '1ae2275e-2ca2-42cb-be13-e97b59fbae13' });
}
componentWillMount() {
fetch(
`http://localhost:8080/api/channel/'+this.state.channelId)
.then...
None of them are setting value in url. Maybe someone could tell me what I am doing wrong?

componentWillMount called before componentDidMount
-> so in componentWillMount, this.state.channelId = []
I think, you should set state of channelId in ComponentWillMount and call api in componentDidMount
constructor(props) {
super(props);
this.state = {
channelId: ''
};
componentWillMount() {
this.setState({ channelId: '1ae2275e-2ca2-42cb-be13-e97b59fbae13' });
}
componentDidMount() {
fetch(
`http://localhost:8080/api/channel/'+this.state.channelId)
.then...
And with react 16, react doesn't recommend using componentWillMount in new code (Details: https://reactjs.org/docs/react-component.html#unsafe_componentwillmount)

So the first thing is to set channelId to a string and not an array.
constructor(props) {
super(props);
this.state = {
channelId: ''
}
Let me ask why you want to use componentWillMount... From my experience, it sometimes adds a lifecycle that is not necessarily useful.
Have you tried
constructor(props) {
super(props);
this.state = {
channelId: ''
};
componentDidMount() {
this.getChannelId()
}
getChannelId() {
this.setState({
channelId: '1ae2275e-2ca2-42cb-be13-e97b59fbae13'
});
return fetch( `http://localhost:8080/api/channel/${this.state.channelId}`)
.then(res => {
// your code
})
}
?
I used a "similar" approach for an app of mine:
import React, { Component } from 'react';
import { connect} from 'react-redux';
import { API_BASE_URL } from '../config';
import { Weekday, Weekendday } from './Day';
import './Availability.css';
const currentUserId = localStorage.getItem("id");
export class Availability extends Component {
constructor(props) {
super(props);
this.state = {
availability: {},
loading: false,
error: null
};
}
componentDidMount() {
this.loadAvailability()
}
loadAvailability() {
this.setState({
loading: true
});
return fetch(`${API_BASE_URL}/employee/${currentUserId}/availability`)
.then(res => {
if (!res.ok) {
return Promise.reject(res.statusText);
}
return res.json();
})
.then(availability => {
console.log(availability)
this.setState({
availability,
loading: false
})
})
.catch(err => {
this.setState({
error: 'Could not load availability list',
load: false
})
console.log(this.state.error, err)
})
}
...
Also do you mind sharing the rest of your code for that component so we can see when you need another change of state?
Thanks!

Related

How to get state which comes from props which is got from API in React

What I want to do
When a child component first rendering, I would like to use the value in props from a parent component
Problem
When a child component is first rendered, props is not set to state in the child component
I am a beginner to React. I am trying to use props in order to call API by axios in componentDidMount in a child component. I mean, what I am doing is calling API in a parent component and setting data from this API to a child component as props.
However, when I try to do that, props is not set to state in a child component.
For example, when I retrieve product which has some category, I type localhost:3000/api/parent/?category=1/. But, my console.log shows me localhost:3000/api/parent/?category=undefined because I guess props is not set when a child component first rendering.
Actually, I can see category object in state like below.
I guess props is completely set to state after the child component finish first rendering.
How could I set props which comes from API to state?
Although I tried many solutions I found on the stackoverflow, I got stuck at this problem so long time.
I would like you to tell me some solutions.
Thank you very much.
== == ==
My code is like this.
Parent Component
class Top extends Component {
constructor(props) {
super(props);
this.state = {
loginUser: '',
categories: [],
};
}
async componentDidMount() {
const localhostUrl = 'http://localhost:8000/api/';
const topCategoryList = ['Smartphone', 'Tablet', 'Laptop'];
let passCategoryToState=[]
axios
.get(localhostUrl + 'user/' + localStorage.getItem('uid'))
.then((res) => {
this.setState({ loginUser: res.data });
})
.catch((err) => console.log(err));
await Promise.all(
topCategoryList.map(async (category) => {
await axios.get(localhostUrl + 'category/?name=' + category).then((res) => {
passCategoryToState=[...passCategoryToState, res.data]
console.log(passCategoryToState);
});
})
);
this.setState({categories : passCategoryToState})
}
render() {
if (!this.props.isAuthenticated) {
return <p> Developing now </p>;
}
if (this.state.loginUser === '' ) {
return <CircularProgress />;
} else {
return (
<>
<Header loginUser={this.state.loginUser} />
<Give_Item_List
axiosUrl="http://localhost:8000/api/"
subtitle="Smartphone Items"
loginUser={this.state.loginUser}
category={this.state.categories[0]}
/>
</>
);
}
}
}
export default Top;
And, child component
class Give_Item_List extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
loginUser: this.props.loginUser,
category: this.props.category,
};
}
async componentDidMount() {
let pickedGiveItems;
await this.setState({ loading: true });
await axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.state.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('Not found related to Items'));
this.setState({ loading: false });
}
render() {
if (this.state.loading == true) {
return <CircularProgress />;
}
return <h1>Give_Item_List</h1>;
}
}
export default Give_Item_List;
==============
Edit:Change to componentDidUpdate
componentDidUpdate(prevProps) {
if(prevProps.category != this.props.category){
let pickedGiveItems;
this.setState({ loading: true });
axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('NotFount'));
this.setState({ loading: false });
}
}
It still doesn't work...
In the constructor, this.props is undefined, but you can access the props directly.
constructor(props) {
super(props);
this.state = {
loading: false,
loginUser: props.loginUser,
category: props.category,
};
}
However, I should note now that storing props in state is a common react anti-pattern, you should always consume prop values from this.props where you need them.
For example:
async componentDidMount() {
let pickedGiveItems;
await this.setState({ loading: true });
await axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('Not found related to Items'));
this.setState({ loading: false });
}
You also can't await a react state update since it isn't an async function nor does it return a Promise. Just provide an initial true loading state and toggle false when the fetch request resolves.
class Give_Item_List extends Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
}
async componentDidMount() {
let pickedGiveItems;
await axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('Not found related to Items'));
this.setState({ loading: false });
}
render() {
if (this.state.loading) {
return <CircularProgress />;
}
return <h1>Give_Item_List</h1>;
}
}

How to reload api fetch call on variable change in React js?

I'm creating a block for Wordpress with Gutenberg Editor, which is working on React js.
So I'm calling Wordpress API by apiFetch(), which is same to fetch():
class PortfolioTagsEdit extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
};
}
componentDidMount() {
const { attributes } = this.props;
const { switcher } = attributes;
this.setState({ isLoading: true });
apiFetch( { path: `/wp/v2/${switcher}?post` } )
.then(data => this.setState({ data, isLoading: false }));
}
...
}
For variable switcher I have controllers which are changing the value.
My problem is when I switch the value of switcher I should reload api call, but I don't know how)
Can you help me, please?
Using react hooks you can use useEffect for fetching API.
function PortfolioTagsEdit({ attributes }) {
// state
const [loading, setLoading] = useState(false);
const [data, setData] = useState([])
// here useEffect will run on component mount and every-time attributes.switcher changes
useEffect(() => {
setLoading(true)
apiFetch( { path: `/wp/v2/${switcher}?post` } )
.then(data => {
setLoading(false)
setData(data)
});
}, [attributes.switcher])
return (
....
)
}
The easiest way to do this would be to have the switcher variable in state. You can then implement the componentDidUpdate method to call your apiFetch:
class PortfolioTagsEdit extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
switcher: this.props.attributes.switcher
};
}
componentDidMount() {
this.callAPI()
}
componentDidUpdate(prevProps, prevState) {
if (prevState.switcher !== this.state.switcher) this.callAPI();
}
callAPI() {
const { switcher } = this.state;
this.setState({ isLoading: true });
apiFetch( { path: `/wp/v2/${switcher}?post` } )
.then(data => this.setState({ data, isLoading: false }));
}
...
}
Check out the docs for componentDidUpdate - https://reactjs.org/docs/react-component.html#componentdidupdate
You could also take a look on how to do this using hooks, specifically useEffect -https://reactjs.org/docs/hooks-reference.html#useeffect

How to pass state within state in react native

I want to pass my data array and favorites array which both I am setting in states. I want to pass my favorites array state in my data state. How can I achieve that?? My code looks like this
class Favorites extends Component {
constructor(props) {
super(props);
this.state = {
favorites: [],
data: [],
};
}
axios
.post(
'http://staging.islamicmedia.com.au/wp-json/islamic-media/v1/user/media/library',
data,
)
.then((res) => {
console.log(res.data);
this.setState({
data: res.data,
favorites: res.data.data.favorite.filter((val) => val != null),
});
});
};
You should do that axios call in the componentDidMount:
class Favorites extends Component {
constructor(props) {
super(props);
this.state = {
favorites: [],
data: [],
};
}
componentDidMount() {
axios
.post(
'http://staging.islamicmedia.com.au/wp-json/islamic-media/v1/user/media/library',
data,
)
.then((res) => {
const favs = res.data.data.favorite.filter((val) => val !== null);
this.setState({
data: res.data,
favorites: favs
});
});
};
}

How can I manage a list from Parent component in React and render it?

I have a reactjs application.
In this I want to manage a list from parent component.
This application can add a object to list, delete it from list and show added objects in a table.
My problem is that I can add an object, but must refresh the whole page that it is shown in the list.
The two way binding not work and I don't know how to implement it.
I hope you can help me.
class Wrap extends React.Component{
constructor(){
super();
this.state = {
player: []
};
}
render(){
return(
<div id ="wrapperComponent">
<Table/>
<Create />
</div>
);
}
}
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
player: []
};
this.deletePlayer = this.deletePlayer.bind(this);
}
componentDidMount() {
axios.get('http://localhost:8081/player')
.then(res => {
this.setState({ player: res.data });
console.log(this.state.player);
});
}
deletePlayer(id) {
fetch(`http://localhost:8081/player/${id}`, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(() => {
let updatedPlayers = [...this.state.player].filter(i => i.id !== id);
this.setState({player: updatedPlayers});
});
}
class Create extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
ownerid: ''
};
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
onSubmit = (e) => {
e.preventDefault();
const { name, ownerid} = this.state;
axios.post('http://localhost:8081/player', { name, ownerid})
.then(() => this.setState(() => ({
})))
}
```
Add your .get call in a method in parent component and pass it as props. Use it to refresh your list.
class Wrap extends React.Component {
constructor() {
super();
this.state = {
players: []
};
}
getData = () => {
axios.get('http://localhost:8081/player')
.then(res => {
this.setState({ players: res.data });
});
}
removePlayerFromState = (id) => {
let updatedPlayers = [...this.state.players].filter(i => i.id !== id);
this.setState({players: updatedPlayers});
}
render() {
return (
<div id="wrapperComponent">
<Table getData={this.getData} players={this.state.players} removePlayerFromState={this.removePlayerFromState}/>
<Create getData={this.getData}/>
</div>
);
}
}
class Table extends React.Component {
// use this.props.players
}
class Create extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
ownerid: ''
};
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
onSubmit = (e) => {
e.preventDefault();
const { name, ownerid } = this.state;
axios.post('http://localhost:8081/player', { name, ownerid })
.then(() => this.props.getData())
}
}

Access value from function dispatch on component

I'm new to react.
I have a function, that need to refresh the state according with API request result on my component.
How can i access that value?
Code (Example):
LoginComponent.js
class Login extends React.Component {
constructor(props){
super(props)
this.state = {
username : '',
password : ''
}
}
submit = (e) => {
/* console.logging "Some response"*/
console.log(this.props.doLogin(this.state))
}
render(){
return (
<form onSubmit={this.submit}>/* some login element */</form>
)
}
}
export default connect(null, {LoginAction})(Login);
LoginAction.js
export function doLogin(state){
return dispatch => {
return axios.post('login', state).then(res =>{
return "Some response";
})
}
}
you can do like this
for example create axios.js
import axios from 'axios';
var instance = axios.create({
baseURL: 'https://www.',
timeout: 1000,
headers: {'Authorization': 'Bearer xxx'}
});
export default instance;
then in your another screen
import React from 'react';
import API from '../axios';
export default class Profile extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
feedback: "",
id: "",
errors: {},
};
}
postComment = () => {
API.post(`/new-comment`, {
id: this.state.id,
feedback: this.state.feedback,
})
.then(res => res.data)
.then((response)=> {
this.setState({
feedback: '',
error: response.error || null,
})
}).catch(error => {console.log(error), this.setState({ error});});
}

Resources