same condition statement on multiple pages in next js - javascript

I am using next js in my project
when i fetch from my server using useswr hook then there is certain condition to return on the page for example
dashboard.js
import InnerNavbar from "../components/InnerNavbar";
import DashboardLoadingSkeleton from "../components/DashboardLoadingSkeleton";
import DashBoardData from "../components/DashBoardData";
import useSWR, { mutate } from "swr";
const fetcher = async () => await fetch(`${process.env.NEXT_PUBLIC_URL}/fetchchallenges`, {
method: "POST",
credentials: 'include'
}).then((res) => res.json());
const dashboard = () => {
const { data, error } = useSWR("/dashboard", fetcher, { dedupingInterval: 40000 });
if (!data) {
if (!data.Errors) {
return (<><InnerNavbar /><DashBoardData data={data} mutate={mutate} /></>);
} else if (data.Errors === "Not Approved") {
return (<>{location.replace('/notapproved')} <center><h1>Not Approved By Admin</h1></center></>)
}else {
return (<>{location.replace('/logout')} <center><h1>Redirecting...</h1></center></>)
}
} else {
return (
<>
<InnerNavbar />
<DashboardLoadingSkeleton />
</>
)
}
};
export default dashboard;
now i want to need this same conditional statement in multiple pages to return but i don't known how to create a separate function for that.

I think you can use react Higher-Order Components
here is sth that I made:
import useSWR, { mutate } from "swr";
const fetcher = async () => await fetch(`${process.env.NEXT_PUBLIC_URL}/fetchchallenges`, {
method: "POST",
credentials: 'include'
}).then((res) => res.json());
const withSwrData = ({Component,endpoint}) => {
const { data, error } = useSWR(endpoint, fetcher, { dedupingInterval: 40000 });
if (!data) {
if (!data.Errors) {
return (<Component data={data} mutate={mutate} />);
} else if (data.Errors === "Not Approved") {
return (<>{location.replace('/notapproved')} <center><h1>Not Approved By Admin</h1></center></>)
}else {
return (<>{location.replace('/logout')} <center><h1>Redirecting...</h1></center></>)
}
} else {
return (
<>
<Component />
</>
)
}
};
export default withSwrData;
and use it in dashboard in this way :
import InnerNavbar from "../components/InnerNavbar";
import DashboardLoadingSkeleton from "../components/DashboardLoadingSkeleton";
import DashBoardData from "../components/DashBoardData";
import withSwrData from "../withSwrData"
const dashboard = ({data,mutate}) => {
return (<>
<InnerNavbar />
{data ? <DashBoardData data={data} mutate={mutate} /> : <DashboardLoadingSkeleton /> }
</>)
};
export default withSwrData(dashboard,"/dashboard");

Related

facing error of bad request even thought the query is same

Well i am trying to reduce the line of code at once refactoring the code
import React, { Component } from 'react';
import { Loader } from '../../components';
import './ProductListing.scss';
import { ProductCard } from '../../components';
import { productQuery } from '../../utls/queries';
export class ProductListing extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
products: [],
categoryId: '',
};
}
componentDidMount() {
const currentUrl = window.location.pathname;
const id = currentUrl.replace('/', '');
this.setState({ categoryId: id });
const newQuer = { ...productQuery };
const query = `
query{
categories {
name
products {
id,
name,
brand,
inStock,
gallery,
category,
prices {
amount,
currency {
label,
symbol
}
}
}
}
}
`;
console.log(query === productQuery);
console.log(productQuery);
fetch('http://localhost:4000', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
query,
}),
})
.then((response) => {
return response.json();
})
.then((data) => {
this.setState({
products: data.data,
loading: false,
});
});
}
render() {
if (this.state.loading === true) {
return <Loader />;
} else {
return (
<div>
<h2 className='page__listing__title'>
{this.state.categoryId[0].toUpperCase() +
this.state.categoryId.substring(1)}
</h2>
<div className='productlisting__page'>
{this.state.products.categories.map((item, index) => (
<div key={index}>
{item.name === this.state.categoryId ? (
<div className='product__listing__card'>
{item.products.map((product, i) => (
<ProductCard product={product} key={i} />
))}
</div>
) : (
''
)}
</div>
))}
</div>
</div>
);
}
}
}
export default ProductListing;
In the process of reducing code i see that the query is taking a lot of places so i decided to write it at separate place now i am importing it as productQuery when i console.log(productQuery===query) it says true but the place where i am using the query to fetch data i use productQuery it just give bad error i cant understand ...
if some one have much better idea i really like if you can suggest me much better ways by which i can reduce the lines of code
I think what's happening is you're accidentally destructuring the query you import, when you say
const newQuery = {...productQuery}
productQuery is simply a string (as proven by your console log that stays productQuery === query).
newQuery is an object that destructures the string, and trying to use that would likely result in a failure.

Why is one of my child components able to get handleClick() but the others are not?

PROBLEM
I am swapping components based on state in Dashboard(parent) component and passing props to all of them. When I log in using wholesaler the app is running without problems but when i log in with retailer account the app return
TypeError: this.props.handleClick is not a function
when i click on a button-handleClick() -> switch components through handleClick which changes state
My components are almost identical and i have no idea where this is coming from.
Thank you in advance! :)
Files:
Dashboard.js
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { Retailers } from './_components/Retailers'
import { Locations } from './_components/Locations'
import { Products } from './_components/Products'
class Dashboard extends Component {
constructor(props) {
super(props)
this.state = {
chosenRetailerId: null,
chosenLocationId: null,
mountComponent: ''
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount() {
switch (this.props.user.type) {
case 'wholesaler':
this.setState({ mountComponent: "retailers" })
break;
case 'retailer':
this.setState({ mountComponent: "locations" })
break;
case 'location':
this.setState({ mountComponent: "products" })
break;
default:
break;
}
}
handleClick(id, shouldMountComponent) {
switch (shouldMountComponent) {
case 'locations':
this.setState({
mountComponent: shouldMountComponent,
chosenRetailerId: id
})
break;
case 'products':
this.setState({
mountComponent: shouldMountComponent,
chosenLocationId: id
})
break;
default:
break;
}
}
render() {
const { user } = this.props
const { chosenLocationId, chosenRetailerId, mountComponent } = this.state
return (
<div className="dashboard">
{user.type === 'wholesaler' &&
<div className="wholesaler">
<h1>Wholesaler</h1>
<h3>{user._id}</h3>
{this.state.mountComponent === 'retailers' &&
<Retailers mountComponent={mountComponent} handleClick={this.handleClick} />
}
{this.state.mountComponent === 'locations' &&
<Locations retailerId={chosenRetailerId} locationId={chosenLocationId} mountComponent={mountComponent} handleClick={this.handleClick} />
}
{this.state.mountedComponent === 'products' &&
<Products locationId={chosenLocationId} mountComponent={mountComponent}/>
}
</div>
}
{user.type === 'retailer' &&
<div className="retailers">
<h1>Retailer {user._id}</h1>
<Locations locationId={chosenLocationId}/>
</div>
}
{user.type === 'location' &&
<div className="locations">
<h1>Location {user._id}</h1>
<Products />
</div>
}
<p>You're logged in with React & JWT!!</p>
<p>
<Link to="/login">Logout</Link>
</p>
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return {
user
}
}
const connectedDashboard = connect(mapStateToProps)(Dashboard)
export { connectedDashboard as Dashboard }
Retailers.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Retailers extends Component {
state = {
retailers: []
}
componentDidMount() {
const { user } = this.props
const requestOptions = {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + user.token }
}
fetch(`http://localhost:4000/retailers/by-wholesaler/${user._id}`, requestOptions)
.then(result => result.json())
.then(result => {
this.setState({
retailers: result
})
})
}
render() {
const { retailers } = this.state
return (
<div className="retailers">
{retailers.map((retailer, index) =>
<button key={index} onClick={() => this.props.handleClick(retailer._id, 'locations')}>{retailer.name}</button>
)}
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return { user }
}
const connectedRetailers = connect(mapStateToProps)(Retailers)
export { connectedRetailers as Retailers }
Locations.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Locations extends Component {
state = {
locations: []
}
componentDidMount() {
const { user } = this.props
const requestOptions = {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + user.token }
}
const retailerId = (user.type === 'retailer') ? user._id : this.props.retailerId
console.log(retailerId)
fetch(`http://localhost:4000/locations/by-retailer/${retailerId}`, requestOptions)
.then(result => result.json())
.then(result => {
this.setState({
locations: result
})
})
}
render() {
const { locations } = this.state
return (
<div className="locations">
{locations.map((location, index) =>
<button key={index} onClick={() => this.props.handleClick(location._id, 'products')}>{location.name}</button>
)}
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return { user }
}
const connectedLocations = connect(mapStateToProps)(Locations)
export { connectedLocations as Locations }
You have to pass handleCLick to location as a prop. You do that in you wholesaler case (passing it to the retailer component), but not when using the Locations component
You didn't pass handleClick as a prop :)
<Retailers handleClick={this.handleClick} />
<Locations handleClick={this.handleClick} />
So prop is undefined and you can't call it as a function.
Check the locations.map function in your Locations.js.
Your are passing a so called thisArg to the map function, so it is no longer using the right context.
This should work:
<div className="locations">
{locations.map((location, index) =>
<button key={index} onClick={() =>
this.props.handleClick(location._id, 'products')}>
{location.name}
</button>
)}
</div>
Also, think about using the uuid package for your iteration keys. Now you are using an index and that will not be unique if you do so in another iteration too (not the case yet so).

React Expected an assignment or function call and instead saw an expression

I'm trying to render the data from my database get this instead Failed to compile.
./src/components/list-pets.component.js
Line 38:5: Expected an assignment or function call and instead saw an expression no-unused-expressions
Search for the keywords to learn more about each error.enter code here
Here is my code from the trouble component
import React, { Component } from 'react';
import axios from 'axios';
export default class ListPets extends Component {
constructor(props) {
super(props);
this.state = {
pets: []
};
}
componentDidMount = () => {
this.getPets();
};
getPets = () => {
axios.get('http://localhost:5000/pets')
.then((response) => {
const data = response.data;
this.setState({ pets: data });
console.log('Data has been received!');
})
.catch((err) => {
console.log(err);
});
}
displayPet = (pets) => {
if (!pets.length) return null;
return pets.map((pet, index) => {
<div key={index}>
<h3>{pet.name}</h3>
<p>{pet.species}</p>
</div>
});
};
render() {
console.log('State: ', this.state);
return (
<div className='adopt'>
{this.displayPet(this.state.pets)}
</div>
)
}
}
You need to return a value at each pets.map iteration, currently you’re returning undefined.
return pets.map((pet, index) => {
return (
<div key={index}>
<h3>{pet.name}</h3>
<p>{pet.species}</p>
</div>
)
});
You have to wait until fetching data is completed.
You should have to define the loading bar while fetching.
class App extends Component {
constructor() {
super();
this.state = {
pageData: {},
loading: true
}
this.getData();
}
async getData(){
const res = await fetch('/pageData.json');
const data = await res.json();
return this.setState({
pageData: data,
loading: false
});
}
componentDidMount() {
this.getData();
}
render() {
const { loading, pageData } = this.state;
if (loading){
return <LoadingBar />
}
return (
<div className="App">
<Navbar />
</div>
);
}
}

Fetching data from server through Redux (Action & Reducer) fails to store the data in the State

I'm trying to fetch data through Redux (with actions & reducers) and store it in a ReactTable
Here is the Table :
// MisleadLeadsTable
import React from "react";
import "react-table-v6/react-table.css";
import ReactTable from "react-table-v6";
import { connect } from "react-redux";
import {
getLeadsNotValid,
updateSpecificNotValidLead
} from "../../actions/leads";
import Spinner from "../layout/Spinner";
class MisleadLeadsTable extends React.Component {
constructor(props) {
super();
const { getLeadsNotValid } = props;
// Going to get data from the Server
// Call the Action and use the Reducer
getLeadsNotValid();
// Later put the data in the state
this.state = {
data: []
};
this.renderEditable = this.renderEditable.bind(this);
}
componentDidMount() {
// TODO
const { leadsNotValid } = this.props;
this.setState({
data: leadsNotValid
});
}
// Edit the cells
renderEditable(cellInfo) {
return (
<div
style={{ backgroundColor: "#fafafa" }}
contentEditable
suppressContentEditableWarning
onBlur={e => {
const data = [...this.state.data];
data[cellInfo.index][cellInfo.column.id] = e.target.innerHTML;
this.setState({ data });
}}
dangerouslySetInnerHTML={{
__html: this.state.data[cellInfo.index][cellInfo.column.id]
}}
/>
);
}
render() {
// loading data or not
const { loadingData } = this.props;
// This "data" should hold the fetched data from the server
const { data } = this.state;
return (
<div>
{loadingData ? (
<Spinner />
) : (
<div>
<ReactTable
data={data}
columns={[
{
Header: "Business Name",
accessor: "BusinessName"
// Cell: this.renderEditable
}
]}
defaultPageSize={10}
className="-striped -highlight"
/>
<br />
</div>
)}
</div>
);
}
}
const mapStateToProps = state => ({
loadingData: state.leadReducer.loadingData,
leadsNotValid: state.leadReducer.leadsNotValid
});
const mapDispatchToProps = { getLeadsNotValid, updateSpecificNotValidLead };
export default connect(mapStateToProps, mapDispatchToProps)(MisleadLeadsTable);
However when I try to store the data in the State (in componentDidMount) it always comes back empty , and when the table is being rendered it gets an empty array.
It is crucial to store the data in the State because I'm trying to implement an editable table.
The data is stored in leadsNotValid , and if I do :
<ReactTable
data={leadsNotValid} // Notice !! Changed this
columns={[
{
Header: "Business Name",
accessor: "BusinessName"
// Cell: this.renderEditable
}
]}
defaultPageSize={10}
className="-striped -highlight"
/>
Then the data is presented successfully to the user , however it's not in the State of the component.
How can I put the leadsNotValid in the State using setState ?
Here are the Action & Reducer if it's needed (THEY WORK GREAT !) :
Action :
import axios from "axios";
import {
REQUEST_LEADS_NOT_VALID,
REQUEST_LEADS_NOT_VALID_SUCCESS,
UPDATED_SUCCESSFULLY_A_NOT_VALID_LEAD_THAT_NOW_IS_VALID,
UPDATE_A_SINGLE_NOT_VALID_LEAD
} from "./types";
export const updateSpecificNotValidLead = updatedLead => async dispatch => {
dispatch({
type: UPDATE_A_SINGLE_NOT_VALID_LEAD
});
const config = {
headers: {
"Content-Type": "application/json"
}
};
const body = JSON.stringify({ updatedLead });
const res = await axios.post(
".......API/Something1/....",
body,
config
);
if (res !== null && res.data !== null) {
dispatch({
type: UPDATED_SUCCESSFULLY_A_NOT_VALID_LEAD_THAT_NOW_IS_VALID
});
}
};
export const getLeadsNotValid = () => async dispatch => {
dispatch({
type: REQUEST_LEADS_NOT_VALID
});
const res = await axios.get(".......API/Something2/....");
if (res !== null && res.data !== null) {
dispatch({
type: REQUEST_LEADS_NOT_VALID_SUCCESS,
payload: res.data
});
}
};
Reducer :
import {
GET_MAIN_LEADS_SUCCESS,
REQUEST_MAIN_LEADS,
RELOAD_DATA_MAIN_LEADS_TABLE,
REQUEST_LEADS_NOT_VALID,
REQUEST_LEADS_NOT_VALID_SUCCESS,
UPDATE_A_SINGLE_NOT_VALID_LEAD,
UPDATED_SUCCESSFULLY_A_NOT_VALID_LEAD_THAT_NOW_IS_VALID
} from "../actions/types";
const initialState = {
mainLeadsClients: [],
loadingData: null, // general loader
reloadMainLeadTable: 0,
reloadMisleadTable: 0,
leadsNotValid: []
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case REQUEST_LEADS_NOT_VALID:
return {
...state,
loadingData: true
};
case REQUEST_LEADS_NOT_VALID_SUCCESS:
return {
...state,
loadingData: false,
leadsNotValid: payload
};
case UPDATE_A_SINGLE_NOT_VALID_LEAD:
return {
...state,
loadingData: true
};
case UPDATED_SUCCESSFULLY_A_NOT_VALID_LEAD_THAT_NOW_IS_VALID:
return {
...state,
reloadMisleadTable: state.reloadMisleadTable + 1,
loadingData: false
};
// ... more
default:
return state;
}
}
You may have to write super(props) instead of super() in order to access props in the constructor.

Is there a way to continuously get an value from a redux store one at a time? react redux

i have a async fetch that gets values like A001, A002, names and so on from an API. But sometimes i get 3 or more values with 1 api fetch and i loose some because i show only 3 values at a time in my react component.
So i look for a way to continuously show 1 entry from the store for like 2 seconds and then the next entry and so on.
Can someone please help me here?
Actions
let lastId = 0;
let pathArray = window.location.pathname.split('/');
export const fetchLastId = () => dispatch => {
const url = '/api/display/sites/' + pathArray[3] + '/displays/' + pathArray[5] + '/show';
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Authorization': ''
},
'Content-Type': 'application/json'
}).then(function(response) {
return response.json();
}).then(function(data) {
if (data.length) {
lastId = data[0].id;
} else {
lastId = 0;
}
console.log('Die Letzte ID war ' + lastId);
}).catch(function(error) {
console.log('Fehler: ', error);
})
}
export const fetchLastCalls = () => dispatch => {
const url = '/api/display/sites/' + pathArray[3] + '/displays/' + pathArray[5] + '/calls?id_greater_than=' + lastId;
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Authorization': ''
},
'Content-Type': 'application/json'
}).then(function(response) {
return response.json();
}).then(function(data) {
data.reverse();
if (data.length) {
for (let item of data) {
switch (item.service_id) {
case 24:
dispatch({ type: 'SERVICE_1', payload: item })
break;
case 25:
dispatch({ type: 'SERVICE_2', payload: item })
break;
default:
console.log('Aufruf im Falschen Dienst getätigt.')
}
lastId = item.id;
}
} else {
console.log('Keine neuen Aufrufe.');
}
}).catch(function(error) {
console.log('Fehler: ', error);
})
}
Reducer
let initialState = [];
function service1(state = initialState, action) {
if (action.type === 'SERVICE_1') {
return [action.payload, ...state];
}
return state;
}
export default service1;
Container
import React from 'react';
import { connect } from 'react-redux';
import { NewCall } from '../components/NewCall';
import { LastCall } from '../components/LastCall';
import { fetchLastId , fetchLastCalls } from '../actions/index';
class Service1 extends React.Component {
componentWillMount() {
this.props.onFetchLastId();
}
componentDidMount() {
setInterval(function() {
this.props.onFetchLastCalls();
}.bind(this), 1000);
}
renderNewTicket() {
return this.props.calls.map(call => {
return (
<p key={call.ticket}>{call.ticket}</p>
);
});
}
renderNewPlace() {
return this.props.calls.map(call => {
return (
<p key={call.desk_id}>{call.desk_id}</p>
);
});
}
renderLastTicket() {
return this.props.calls.map(call => {
return (
<p key={call.ticket}>{call.ticket}</p>
)
})
}
renderLastPlace() {
return this.props.calls.map(call => {
return (
<p key={call.desk_id}>{call.desk_id}</p>
)
})
}
componentDidUpdate() {
}
render() {
return(
<div>
<NewCall
call={ this.renderNewTicket() }
place={ this.renderNewPlace() }
/>
<LastCall
call={ this.renderLastTicket() }
place={ this.renderLastPlace() }
rollOn={1}
/>
<LastCall
call={ this.renderLastTicket() }
place={ this.renderLastPlace() }
rollOn={2}
/>
</div>
);
}
}
function mapStateToProps(state) {
return {
calls: state.service1
};
}
let mapDispatchToProps = {
onFetchLastId: fetchLastId,
onFetchLastCalls: fetchLastCalls
}
export default connect(mapStateToProps, mapDispatchToProps)(Service1);
1 Output Component
import React from 'react';
import { Textfit } from 'react-textfit';
import Blink from './Blink';
const inlineStyle = {
width: 945,
height: 249
};
export class NewCall extends React.Component {
render() {
return(
<div>
<div className="flex-item-grey ticketNrGr">
<Textfit mode="multi" style={inlineStyle} className="textfit" max={200}><Blink>{this.props.call[0]}</Blink></Textfit>
</div>
<div className="flex-item-grey platzNrGr">
<Textfit mode="multi" style={inlineStyle} className="textfit" max={200}><Blink>{this.props.place[0]}</Blink></Textfit>
</div>
</div>
);
}
}
Second Output Component
import React from 'react';
import { Textfit } from 'react-textfit';
const inlineStyleCall = {
width: 735,
height: 195
};
const inlineStyleDesk = {
width: 200,
height: 195
};
export class LastCall extends React.Component {
render() {
return(
<div className="flex-container-aufrufKl">
<div className="flex-item-grey ticketNrKl">
<Textfit mode="multi" style={inlineStyleCall} className="textfit" max={200}>{this.props.call[this.props.rollOn]}</Textfit>
</div>
<div className="flex-item-grey platzNrKl">
<Textfit mode="multi" style={inlineStyleDesk} className="textfit" max={200}>{this.props.place[this.props.rollOn]}</Textfit>
</div>
</div>
);
}
}
It sounds to me like it should be the responsibility of the component to trigger a new action to render the next available value. So you could have a component that accepts the value value and a boolean indicating if there are any more values: hasMoreValues.
In your react component, you'll need to make it a class to access the lifecycle hooks and hook into the componentDidMount function:
class MyComponent extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
if(this.props.hasMoreValues) {
setTimeout(this.props.showNextValue, 2000)
}
}
render() {
return (
<div>{this.props.value}</div>
)
}
}
export default connect(
(props) => ({
hasMoreValues: getHasMoreValues(),
value: getNextValue(),
)},
{
showNextValue: () => { type: 'SHOW_NEXT_ACTION' },
},
)
An approach like this means that the trigger is still coming from the application. The next thing to do is update the item to view to be the next one available in your reducer, but I'll leave that up to you.

Categories

Resources