I have two components i.e. Project component and MainContainer. Maincontainer will fetch data again and again using fetchData method, so in this I am able to change the url as well as component when I move forward but during backward it will not change the component but url can change.
Project Component:
conditionalRendering(project) {
let text;
if (project.attributes.folder_id) {
text = <Link to={`/folder/${project.attributes.folder_id}`}>
{project.attributes.name}</Link>
} else {
text = <span>{project.attributes.name}</span>
}
return text;
}
MainContainer Component:
componentDidMount() {
const paths = this.props.location.pathname.split('/')
const id = paths[paths.length - 1]
console.log('componentDidMount')
axios.get(this.state.url, {
params: {
folder_id: id
}
})
.then(response => {
console.log('Axios response of componentdid mount')
console.log(response)
this.setState({
isLoading: !this.state.isLoading,
documents: response.data.data
})
})
}
fetchData(folder_id) {
this.setState({
isLoading: true,
})
console.log('updating state fetch data')
axios.get(this.state.url, {
params: {
folder_id: folder_id
}
})
.then(response => {
console.log('Axios response inside fetchData')
console.log(response)
this.setState({
isLoading: false,
documents: response.data.data,
})
})
}
selectRow(document) {
this.setState({
selectedRow: true,
rowDetails: document
})
}
componentDidUpdate(prevProps, prevState){
console.log('componentDidUpdate')
if (prevState.isLoading === false) {
console.log('if will run isLoading is false')
this.setState({ isLoading: true })
console.log('if will run isLoading is true' )
const paths = this.props.location.pathname.split('/')
const id = paths[paths.length - 1]
axios.get(this.state.url, {
params: {
folder_id: id
}
})
.then(response => {
console.log('Axios response componentdidupdate')
console.log(response)
this.setState({
isLoading: !this.state.isLoading,
documents: response.data.data
})
})
}
}
documentsCollection() {
let documentComponents;
if (this.state.documents.length > 0 ) {
documentComponents = this.state.documents.map(document => {
return (
<tr key={document.id} onClick={() => this.selectRow(document)}>
<span className="file-thumbnail float-right"><i className={document.attributes.is_folder ? 'fas fa-folder' : 'far fa-file'}></i></span>
<td data-label="Name">
<Link to={`/folder/${document.attributes.id}`} onClick={() => this.fetchData(document.attributes.id)}>{document.attributes.filename}</Link>
</tr>
)
})
return documentComponents;
}
}
Router Component:
<Switch>
<Route exact path="/" component= {Project} />
<Route path="/folder/:id" component= {MainContainer} />
</Switch>
If you are already in Maincontainer and only the id value has changed, componentDidMount will not be activated. Please use componentDidUpdate and compare props.
Related
Here is my Search component.
class Search extends Component {
state = {
hcpName: [],
hcps: [],
showTab: false,
searchName: '',
isLoading: false,
page_id: 2,
page_id_name: 1,
hcp_id: 101,
receivedData: [],
nameData: []
}
componentDidMount() {
this.fetchingData();
}
hcpNamesFetch = () => {
return axios.get('/get-hcp-data')
.then((res) => {
const hcps = res.data;
console.log('MD list data: ', res.data)
this.setState({ ...this.state, hcps: hcps, hcpName: Object.values(hcps.hcp_details_concat) })
// console.log('MD name in : ', this.state.hcps.hcp_overview.name)
})
.catch(error => console.error(`Error: $(error)`));
}
dataFetch = () => {
let page_id = this.state.page_id;
let hcp_id = this.state.hcp_id;
console.log('state: ', this.state);
axios.post('/test-json', {
page_id: page_id,
hcp_id: hcp_id
})
.then((res) => {
const dataRequest = res.data;
console.log('State before loading data: ', this.state);
console.log('received data', res.data);
this.setState({ ...this.state, receivedData: res.data });
console.log('State after loading data: ', this.state);
}, (error) => {
console.log(error);
});
}
nameFetch = () => {
let page_id_name = this.state.page_id_name;
let hcp_id = this.state.hcp_id;
console.log('state: ', this.state);
axios.post('/test-json', {
page_id: page_id_name,
hcp_id: hcp_id
})
.then((res) => {
console.log('Name received data', res.data);
this.setState({ ...this.state, nameData: res.data });
console.log('State after loading data from name: ', this.state);
}, (error) => {
console.log(error);
});
}
fetchingData = () => {
axios.all([this.hcpNamesFetch(), this.dataFetch(), this.nameFetch()])
.then(axios.spread((...responses) => {
const responseOne = responses[0];
const responseTwo = responses[1];
const responseThree = responses[2];
console.log(responseOne, responseTwo, responseThree)
}))
.catch(error => console.error(`Error: $(error)`));
}
render() {
return (
<div>
{this.state.receivedData.length !== 0 && <Name data={this.state.receivedData} />}
<div class="row">
<div class="col-12" style={{ padding: 0 }}>
<div class="tabs-container-fluid">
<MidTabs />
<div class="tab-content">
{this.state.receivedData.length !== 0 && <Dashboard data=
{this.state.receivedData} />}
</div>
</div>
</div>
</div>
</div>
As you can see in the code, I'm making a few axios requests. The problem that I'm having currently is that I want to display both the Name and Dashboard component after I get data in the receivedData state. When I comment out the line where I conditionally render Name, it works fine and I can see the Dashboard component after I get data from axios. But when I add the Name component line, I get a cross-origin error like this: "Unhandled Rejection (Error): A cross-origin error was thrown. React doesn't have access to the actual error object in development. See https://reactjs.org/link/crossorigin-error for more information."
Why am I getting that error only for the name component and not for the Dashboard component. Because when I use the Dashboard component individually by cutting out the line of Name component, the application works fine. I want to resolve that erro.
I have get my data from firebase , loop through them and display them to dom.
then I added a delete button and send a delete request using axios and it's delete from firebase but the dom doesn't rerender. I set a deleting state to change it in 'then' block but even when I change the state it dosn't rerender!
what can I do?
class Orders extends Component {
state = {
orders: [],
loading: true,
deleting: false,
};
componentDidMount() {
axios
.get('/order.json')
.then((res) => {
// console.log(res.data);
const fetchedOrders = [];
for (let key in res.data) {
fetchedOrders.push({ ...res.data[key], id: key });
}
this.setState({ loading: false, orders: fetchedOrders });
})
.catch((err) => {
this.setState({ loading: false });
});
}
deleteHandler = (id) => {
axios.delete(`/order/${id}.json`).then((res) => {
this.setState({ deleting: true });
console.log(res, this.state.deleting);
});
};
render() {
return (
<div>
{this.state.orders.map((order) => (
<Order
key={order.id}
ingredients={order.ingredient}
price={order.price}
id={order.id}
delete={() => this.deleteHandler(order.id)}
/>
))}
</div>
);
}
}
You have to update the orders state while calling deleteHandler! Try this code!
import React from 'react';
import axios from 'axios';
// YOUR OTHER IMPORT GOES HERE
class Orders extends Component {
constructor(props) {
this.state = {
orders: [],
loading: true,
deleting: false,
}
}
componentDidMount() {
axios
.get('/order.json')
.then((res) => {
// console.log(res.data);
const fetchedOrders = [];
for (let key in res.data) {
fetchedOrders.push({ ...res.data[key], id: key });
}
this.setState({ loading: false, orders: fetchedOrders });
})
.catch((err) => {
this.setState({ loading: false });
});
}
deleteHandler = (id) => {
this.setState({
orders: this.state.orders.filter(orderValue => orderValue.id !== id)
})
axios.delete(`/order/${id}.json`).then((res) => {
this.setState({ deleting: true });
console.log(res, this.state.deleting);
});
};
render() {
return (
<div>
{this.state.orders.map((order) => (
<Order
key={order.id}
ingredients={order.ingredient}
price={order.price}
id={order.id}
delete={() => this.deleteHandler(order.id)}
/>
))}
</div>
);
}
}
I am developing a project with Moviedb api. I created the movie list under the name Movie component. I make my api requests in this component. From the Movie component to the MovieInfo component, I send the release date of the movie and the genres of the movie via props.
But I cannot apply substring and map methods to these properties that come to me in the MovieInfo component with props.
class Movie extends Component {
state = {
movie: [],
loading: false,
actors: [],
directors: [],
visible : 6 // This state is for how many actors rendered.
}
componentDidMount() {
this.setState({
loading: true
})
let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`
let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
this.getMovieWithId(moviesEndPoint);
this.getDirectorsAndActors(creditsEndPoint);
}
getMovieWithId = moviesEndPoint => {
fetch(moviesEndPoint)
.then(response => response.json())
.then((movie) => {
// console.log(movie);
if (movie.overview !== "" && !movie.status_code) {
this.setState({
movie,
loading: false
})
}
else { // if have not turkish overview fetch this
let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
fetch(engEndPoint)
.then(response => response.json())
.then((movie) => {
this.setState({
movie
})
})
}
})
}
getDirectorsAndActors = creditsEndPoint => {
fetch(creditsEndPoint)
.then(response => response.json())
.then((credits) => {
// console.log(credits)
const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
// console.log(filterDirector)
this.setState({
actors: credits.cast,
directors: filterDirector[0].name,
loading: false
})
})
}
render() {
const { movie, loading, actors, directors, visible } = this.state
const { location } = this.props
return (
<>
{
loading ? <Spinner /> : null
}
{this.state.movie ?
<MovieInfo
movieInfo={movie}
actors={actors}
directors={directors}
searchWord={location.searchWord}
visible = {visible}
loadMore = {this.loadMore}
loading = {loading}
/> : null
}
{
!actors && !loading ? <h1>Film Bulunamadı! </h1> : null
}
</>
)
}
}
This is the non-working code inside my MovieInfo component and my errors like this :
TypeError: Cannot read property 'substring' of undefined
TypeError: Cannot read property 'map' of undefined
const MovieInfo = ({ movieInfo, searchWord, directors, actors, visible, loadMore, loading }) => {
const editReleaseDate = (date) => { //? Idk why doesn't work !
// return date.substring(5).split("-").concat(date.substring(0,4)).join("/")
return date
// console.log(date)
// return date;
}
return (
<Col sm={5} className="movieInfo p-4 animated fadeInRightBig">
<p className = "movie-title" > {movieInfo.title} </p>
<h5 className = "mb-4 text-warning">Yayınlanma Tarihi: <span className = "text-light">{editReleaseDate(movieInfo.release_date)}</span></h5>
<h5 className = "text-warning">Açıklama</h5>
<p>{movieInfo.overview} </p>
<ProgressBar label={`IMDB: ${movieInfo.vote_average}`} animated now = {`${movieInfo.vote_average}`} min={0} max={10} />
<h5 className = "text-warning mt-3">Türü:
{ //? Idk why doesn't work !
// movieInfo.genres.map((genre, i) => {
// return <span key = {i} >{genre.name}</span>
// })
}
</h5>
<h5 className ="mt-2 text-warning">Yönetmen: <span className = "text-light">{directors} </span> </h5>
<div> <i className="fas fa-film fa-5x"></i> </div>
</Col>
)
You have 1 loading state for 2 api calls so once one is finishing it is telling the component that it is done loading even if the second has finished. I split it up into 2 different loading states, loadingMovie & loadingActors.
class Movie extends Component {
state = {
movie: [],
loadingMovie: false,
loadingActors: false,
actors: [],
directors: [],
visible : 6 // This state is for how many actors rendered.
};
componentDidMount() {
this.setState({
...this.state,
loadingMovie: true,
loadingActors: true,
});
let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`;
let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
this.getMovieWithId(moviesEndPoint);
this.getDirectorsAndActors(creditsEndPoint);
}
getMovieWithId = moviesEndPoint => {
fetch(moviesEndPoint)
.then(response => response.json())
.then((movie) => {
// console.log(movie);
if (movie.overview !== "" && !movie.status_code) {
this.setState({
movie,
loadingMovie: false
})
}
else { // if have not turkish overview fetch this
let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
fetch(engEndPoint)
.then(response => response.json())
.then((movie) => {
this.setState({
movie,
loadingMovie: false
});
})
}
})
}
getDirectorsAndActors = creditsEndPoint => {
fetch(creditsEndPoint)
.then(response => response.json())
.then((credits) => {
// console.log(credits)
if (credits && credits.crew) {
const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
// console.log(filterDirector)
this.setState({
actors: credits.cast,
directors: filterDirector[0].name,
loadingActors: false
})
} else {
console.log('bad credits');
}
})
}
render() {
const { movie, loadingActors, loadingMovie, actors, directors, visible } = this.state;
const { location } = this.props;
return (
<>
{loadingActors || loadingMovie ? <Spinner /> :
(movie.length && actors.length) ?
<MovieInfo
movieInfo={movie}
actors={actors}
directors={directors}
searchWord={location.searchWord}
visible = {visible}
loadMore = {this.loadMore}
loading = {(loadingActors || loadingMovie)}
/> : null
}
{
actors.length && !loadingActors ? <h1>Film Bulunamadı! </h1> : null
}
</>
);
}
}
I have a react component that is in charge of performing a network request using fetch. The API response will be shown on cards within the component.I have defined the structure of the response in the state as movimientos. But when updating the state inside filtrarDatos function with the response, an infinite loop is created and fetch requests are performed infinitely.
Here is my code:
export class Datepicker extends Component {
constructor(props) {
super(props)
this.state = {
startDate: "",
endDate: "",
focusedInput: "",
movimientos: {}
}
}
filtrarDatos(startDateString, endDateString) {
if (startDateString !== '' && endDateString !== '') {
const empresa = {
FECHA_INICIAL: startDateString,
FECHA_FINAL: endDateString
};
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(empresa)
}
fetch('http://localhost:4000/api/movimiento/filtrarfecha', options)
.then((res) => res.json())
.then((data) => {
const { movimientos } = data
console.log({ movimientos })
this.setState({ movimientos })
})
.catch((err) => console.log(err))
}
}
render() {
const endDateString = this.state.endDate && this.state.endDate.format('YYYY-MM-DD') + "T13:47:14.985+00:00";
const startDateString = this.state.startDate && this.state.startDate.format('YYYY-MM-DD') + "T13:47:14.985+00:00";
return (
<div className="DatePicker">
<DateRangePicker
startDate={this.state.startDate} // momentPropTypes.momentObj or null,
endDate={this.state.endDate} // momentPropTypes.momentObj or null,
onDatesChange={({ startDate, endDate }) => this.setState({ startDate, endDate })} // PropTypes.func.isRequired,
focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
endDatePlaceholderText={"Fecha inicial"}
startDatePlaceholderText={"Fecha final"}
displayFormat={"DD/MM/YYYY"}
numberOfMonths={1}
isOutsideRange={() => false}
showClearDates={true}
/>
{this.filtrarDatos(startDateString, endDateString)}
</div>
)
}
}
To be more clear the error is in the following part of the code, if I comment on the status update the program works correctly and only makes a single request. I am new to react and I cannot understand what is happening.
.then((data) => {
const { movimientos } = data
console.log({ movimientos })
this.setState({ movimientos })
})
This is a screenshot of my console during infinite network requests
Its happening because this.filtrarDatos is being called after each re-render (state changes), creating a infinite loop (change data, render, change data, rend...)
You can move the { this.filtrarDatos(startDateString, endDateString) } to componentDidMount:
Remove { this.filtrarDatos(startDateString, endDateString) }
Add this lifecycle function, after constructor:
componentDidMount() {
const endDateString = this.state.endDate && this.state.endDate.format('YYYY-MM-DD') + "T13:47:14.985+00:00";
const startDateString = this.state.startDate && this.state.startDate.format('YYYY-MM-DD') + "T13:47:14.985+00:00";
this.filtrarDatos(startDateString, endDateString);
}
You are calling {this.filtrarDatos(startDateString, endDateString)} in your render body, then in this method you update state, so it creates an infinite loop because react rerender your component after state changes.
I have this problem: for example, I will search for the phrase ab for 45 results. How to set pagination to include only 45 results, not all elements? He is currently looking for 45 items for me. But when I go to the other side, it includes all the elements for me, not just the ones I searched for.
class App extends Component {
constructor() {
super();
this.state = {
todos: []
};
}
searchTodo = debounce((query) => {
this.setState({
query
})
this.getTodo((query), 200)
})
getTodos = (number) => {
const params = {
expand: 'project',
'per-page': 20,
'page': number
}
axios({
url: 'https://jsonplaceholder.typicode.com/todos',
method: "GET"
})
.then(res => {
this.setState({
todos: res.data
});
})
.catch(error => {
console.log(error);
})
}
handlePage = (number) => {
this.getTodos(number);
}
render() {
return (
<div>
<Hello name={this.state.name} />
<p>
<SearchInput onChange={e => this.searchTodo(e)} />
</p>
<Pagination
itemsCountPerPage={20}
totalItemsCount={this.state.todos.length}
onChange={this.handlePage}
/>
</div>
);
}
}