How do you reset a loading bar in react JS? - reactjs

Just a quick problem here. Was finishing a project that I had asked before about here (How to pass values between components in React JS?) and had another question. In the machine component here I need a loading bar, and the teacher showed us this as an example: https://codepen.io/AaronCoding/pen/GjVaGp. I have modified it so it works when values are pressed rather than off a button press but I need it to reset so when the user presses another button it "loads" again. I have tried resting the progress variable to 0 but that just seems to cause the loading bar to get stuck in a loop.
import React, { Component } from 'react';
class CoffeeMachine extends Component {
state = {
brewing: "Now Brewing: Nothing",
progress: 0,
speed: 1,
color: "#ff0050",
frame: this.frame.bind(this),
green: this.green.bind(this),
red: this.red.bind(this)
}
frame() {
if (this.state.progress < 100){
this.setState((prevState, props) => ({
progress: prevState.progress + this.state.speed,
color: "#" + this.red() + this.green() + "50"
}));
console.log(this.state.color);
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
green() {
let progress = this.state.progress;
progress *= 2.55;
progress = Math.round(progress);
progress = progress.toString(16);
return progress;
}
red() {
let progress = this.state.progress;
progress *= 2.55;
progress = Math.round(progress);
progress = 255 - progress;
progress = progress.toString(16);
return progress;
}
brewCoffee() {
this.setState({brewing: "Now brewing: " + this.props.coffee})
setTimeout(() => {this.brewingComplete()}, 5000);
this.interval = setInterval(() => this.frame(), 50);
}
brewingComplete() {
this.setState({brewing: this.props.coffee + " is done"})
setTimeout(() => {this.brewingComplete()}, 5000);
}
componentWillUpdate(nextProps,nextState) {
if (this.props.coffee !== null && this.state === nextState) {
setTimeout(() => {this.brewCoffee()}, 3000);
}
}
render(){
return(
<div>
{ this.state.brewing}
<div id="myBar" style={{
width: this.state.progress + "%",
backgroundColor: this.state.color
}}>
<div id="label">Loaded {this.state.progress}%</div>
</div>
</div>
)
}
}
export default CoffeeMachine;

In your componentWillUpdate() make sure no brewing is running by checking if progress is equal to zero.
You should also check if the choice of coffee to brew has changed in there.
Then you may clear the interval and set the progress to zero.
Make sure you say brewing is done when it is really done because the timeout for that continues running.
Also, you can't bind your methods in the state. You may bind them directly by using fat arrows or bind them in the constructor (old fashioned).
I would also advise to store brewingDelay and brewingTime in a const as they are used several times for matters that must be "synchronized".
import React, { Component } from "react";
const brewingDelay = 2000;
const brewingTime = 5000;
const initialColor = "#ff0050";
class CoffeeMachine extends Component {
state = {
brewing: "Now Brewing: Nothing",
progress: 0,
speed: 1,
color: initialColor,
frame: null,
green: null,
red: null
};
frame = () => {
if (this.state.progress < 100) {
this.setState((prevState, props) => ({
progress: prevState.progress + this.state.speed,
color: "#" + this.red() + this.green() + "50"
}));
console.log(this.state.color);
}
};
componentWillUnmount() {
clearInterval(this.interval);
}
green = () => {
let progress = this.state.progress;
progress *= 2.55;
progress = Math.round(progress);
progress = progress.toString(16);
return progress;
};
red = () => {
let progress = this.state.progress;
progress *= 2.55;
progress = Math.round(progress);
progress = 255 - progress;
progress = progress.toString(16);
return progress;
};
brewCoffee = () => {
this.setState({ brewing: "Now brewing: " + this.props.coffee });
setTimeout(() => {
this.brewingComplete();
}, brewingTime);
this.interval = setInterval(() => this.frame(), 50);
};
brewingComplete = () => {
if (this.state.progress >= 99)
this.setState({ brewing: this.props.coffee + " is done" });
setTimeout(() => {
this.brewingComplete();
}, brewingTime);
};
componentWillUpdate(nextProps, nextState) {
if (
this.props.coffee !== undefined &&
nextProps.coffee !== this.props.coffee &&
this.state.progress !== 0
) {
clearInterval(this.interval);
setTimeout(() => {
this.setState({ progress: 0, color: initialColor }, () => {});
}, brewingDelay);
}
if (this.props.coffee !== null && this.state === nextState) {
setTimeout(() => {
this.brewCoffee();
}, brewingDelay);
}
}
render() {
return (
<div>
{this.state.brewing}
<div
id="myBar"
style={{
width: this.state.progress + "%",
backgroundColor: this.state.color
}}
>
<div id="label">Loaded {this.state.progress}%</div>
</div>
</div>
);
}
}
class ParentChoice extends React.PureComponent {
state = {};
render() {
return (
<React.Fragment>
<button onClick={() => this.setState({ coffee: "Arabica" })}>
Arabica
</button>
<button onClick={() => this.setState({ coffee: "Robusta" })}>
Robusta
</button>
<CoffeeMachine coffee={this.state.coffee} />
</React.Fragment>
);
}
}
export default ParentChoice;

Related

How to update state so that my timer will run after video load

I am newbie on react. I am bit stuck in problem and need to know some pointers regarding state update.
PROBLEM: I am making the video on load and add the skip button for removing the video from screen. Video will be played through HTML under the modal. Problem is my video load in 2 or 3 sec after the page refresh and modal will open prior to load video. I have set the timer from 5 seconds which is in reverse format like 5, 4, 3, 2, 1, skip
But due to slow/late video load, timer run in background and in front side when video display sometime it sees 3, 2, 1, skip
What I am looking for is when my video start load then only my timer function trigger.
I have tried onLoad(), onStart() to update the flag state from false to true and on componentDidMount -> load the page according to the state but not getting luck
This is my code:
export default class FullScreenAds extends React.Component {
constructor(props) {
super(props);
this.state = {
isFullPageVideoModalEnabled: false,
timerForVideo: 7,
isDisabled: true,
};
},
async componentDidMount() {
const uuid = Math.round((new Date()).getTime() / 1000);
let getUserSession = localStorage.getItem("gid");
if (getUserSession === null || getUserSession.length < 1) {
localStorage.setItem("gid", uuid);
}
this.setState({
isFullPageVideoModalEnabled: true,
getSession: getUserSession
})
this.startTimer()
},
async startTimer() {
// await sleep(3000);
this.timer = setInterval(() => {
const { timerForVideo } = this.state
if (timerForAds > 0) {
this.setState(({ timerForVideo }) => ({
timerForVideo: timerForVideo - 1
}))
}
if (timerForAds === 0) {
this.setState({ isDisabled: false })
clearInterval(this.timer)
}
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
return (
// run the modal based on state and load the video
<video width="100%" height="auto" autoPlay playsInline loop>
<source type="video/mp4" src="video/src/url" />
</video>
)
}
}
Create a reference with React.createRef() and attach the reference to the video, then listen for the onplay event on the video and start the timer when the onplay event fires:
Try this:
export default class FullScreenAds extends React.Component {
constructor(props) {
super(props);
this.videoRef = React.createRef()
this.state = {
isFullPageVideoModalEnabled: false,
timerForVideo: 7,
isDisabled: true,
};
},
async componentDidMount() {
const uuid = Math.round((new Date()).getTime() / 1000);
let getUserSession = localStorage.getItem("gid");
if (getUserSession === null || getUserSession.length < 1) {
localStorage.setItem("gid", uuid);
}
this.setState({
isFullPageVideoModalEnabled: true,
getSession: getUserSession
})
this.videoRef.current.onplay = () => this.startTimer();
},
async startTimer() {
// await sleep(3000);
this.timer = setInterval(() => {
const { timerForVideo } = this.state
if (timerForAds > 0) {
this.setState(({ timerForVideo }) => ({
timerForVideo: timerForVideo - 1
}))
}
if (timerForAds === 0) {
this.setState({ isDisabled: false })
clearInterval(this.timer)
}
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
return (
// run the modal based on state and load the video
<video ref={this.videoRef} width="100%" height="auto" autoPlay playsInline loop>
<source type="video/mp4" src="video/src/url" />
</video>
)
}
}
Or you can try using functional component with hooks.
Something like this:
export const FullScreenAds = () => {
const [state, setState] = React.useState({
isFullPageVideoModalEnabled: false,
timerForVideo: 7,
isDisabled: true,
});
const videoRef = React.useRef();
const timerRef = React.useRef();
const startTimer = () => {
timerRef.current = setInterval(() => {
const { timerForVideo } = state;
if (timerForAds > 0) {
setState({
...state,
timerForVideo: state.timerForVideo - 1,
});
}
if (timerForAds === 0) {
setState({ ...state, isDisabled: false });
clearInterval(this.timer);
}
}, 1000);
};
useEffect(() => {
const uuid = Math.round(new Date().getTime() / 1000);
let getUserSession = localStorage.getItem("gid");
if (getUserSession === null || getUserSession.length < 1) {
localStorage.setItem("gid", uuid);
}
setState({
...state,
isFullPageVideoModalEnabled: true,
getSession: getUserSession,
});
videoRef.current.onplay = startTimer;
return clearInterval(timerRef.current);
}, []);
return (
<video
ref={this.videoRef}
width="100%"
height="auto"
autoPlay
playsInline
loop
>
<source type="video/mp4" src="video/src/url" />
</video>
);
};

Cannot read property clientHeight document in jest test cases

I am very new to write test cases, i tried to write test cases for my dashboard page and i am getting Cannot read property 'clientHeight' of undefined error, please see my all dashboard.js page below & my test cases file. please help me on this
getting Error in this line:
var t = window.innerHeight - document.getElementsByClassName('nep-header')[0].clientHeight - 20 + "p
My Dashboard.js page:
import { CompanyDashboard, DeleteCompanyDashboard } from "../../APICall/CompanyDashboard";
import React from "react";import { GetimageUrl } from "../../Common/UtilityFunctions";
import { Table, Modal, Button, Message } from "#maknowledgeservices/neptune";
import './Dashboard.css';
import { dateFormatConversionForSorting } from '../../Common/UtilityFunctions';
import { setTimeout } from "timers";
import Loader from '../../Components/Loader/Loader';
var successMessage = false;
var errorMessage = false;
var showing = true;
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.showing = true;
setTimeout(() => {
var divsToHide = document.getElementsByClassName("nep-table-empty"); //divsToHide is an array
for (var i = 0; i < divsToHide.length; i++) {
divsToHide[i].style.visibility = "hidden"; // or
divsToHide[i].style.display = "none"; // depending on what you're doing
}
}, 10);
this.state = {
visible: false,
DeleteCompStr: "",
DeleteCompID: 0,
columnDefs: [
{
title: "Company", render: "Companyname", fixed: "left", width: 320, sorter: order => (a, b) => {
if (order === 'asc') return a.Companyname.localeCompare(b.Companyname)
return b.Companyname.localeCompare(a.Companyname)
}
},
{
title: 'Year End', width: 95, render: d => this.renderMethod(d.financeYearEndMonth + " " + d.financeYearEnd), sorter: order => (a, b) => {
if (order === 'asc') return dateFormatConversionForSorting(a.financeYearEndMonth + " " + a.financeYearEnd).localeCompare(dateFormatConversionForSorting(b.financeYearEndMonth + " " + b.financeYearEnd))
return dateFormatConversionForSorting(b.financeYearEndMonth + " " + b.financeYearEnd).localeCompare(dateFormatConversionForSorting(a.financeYearEndMonth + " " + a.financeYearEnd))
}
},
{
title: 'LTM Financials', width: 95, render: d => this.renderMethod(d.ltmMonth + " " + d.ltmYear), sorter: order => (a, b) => {
if (order === 'asc') return dateFormatConversionForSorting(a.ltmMonth + " " + a.ltmYear).localeCompare(dateFormatConversionForSorting(b.ltmMonth + " " + b.ltmYear))
return dateFormatConversionForSorting(b.ltmMonth + " " + b.ltmYear).localeCompare(dateFormatConversionForSorting(a.ltmMonth + " " + a.ltmYear))
}
},
{
title: "AccuRate", width: 95, render: s => this.StatusIndicator(s.accurate),
},
{
title: "Financial Trends", width: 95, render: s => this.StatusIndicator(s.finTrend),
},
{
title: "Newsflow Trends", width: 115,
render: (s) => (
<div style={{ cursor: "default" }}>
{this.StatusIndicator(s.newsflow)}
<a className="tooltip" style={{ float: "right" }}
onClick={this.show.bind(this, s)}
><i style={{ cursor: "pointer" }} className="icon-Delete" name="delete"
onMouseOver={({ target }) => target.style.color = '#021155'}
onMouseOut={({ target }) => target.style.color = '#75787B'} /></a>
</div>
),
}
],
companyCount: '',
rowData: [],
res: ""
}
this.show = this.show.bind(this)
}
show(selRowVal) {
this.setState({
visible: true,
})
this.DeleteCompID = selRowVal.id;
this.DeleteCompStr = selRowVal.Companyname;
}
handleOk = () => {
DeleteCompanyDashboard("DeleteCompany/" + this.DeleteCompID).then(responce => {
if (responce.data === true) {
if (successMessage === false) {
successMessage = true;
Message.success(this.DeleteCompStr + ' Company has been deleted successfully', 7, {
onClose: () => {
successMessage = false;
}
});
}
}
else {
if (errorMessage === false) {
errorMessage = true;
Message.error('Server error', 7, {
onClose: () => {
errorMessage = false;
}
});
}
}
this.componentDidMount();
this.setState({
visible: false,
});
});
}
handleCancel = () => {
this.setState({
visible: false,
})
}
renderMethod(params) {
return params.substring(3);
}
handleRemove(selectedValue) {
this.show();
}
StatusIndicator(params) {
switch (params) {
case 'Positive':
return <span style={{ color: '#388E3C' }}><img className="indicaterGap" src={GetimageUrl(params)}></img>{params}</span>
break;
case 'Negative':
return <span style={{ color: '#C62828' }}><img className="indicaterGap" src={GetimageUrl(params)}></img>{params}</span>
break;
case 'Stable':
return <span style={{ color: '#C68700' }}><img className="indicaterGap" src={GetimageUrl(params)}></img>{params}</span>
break;
case 'Neutral':
return <span style={{ color: '#C68700' }}><img className="indicaterGap" src={GetimageUrl(params)}></img>{params}</span>
break;
default:
return <span style={{ color: '#55565A' }}>{params}</span>
break;
}
}
componentDidMount() {
CompanyDashboard("GetCompany").then(responce => {
this.showing = false;
this.setState({
rowData: responce.data,
companyCount: responce.data.length === 0 || undefined ? 0 : responce.data.length
});
});
this.tableHeight();
}
componentDidUpdate(prevProps, prevState) {
if (prevState.companyCount !== this.state.companyCount) {
CompanyDashboard("GetCompany").then(responce => {
this.setState({ rowData: responce.data, companyCount: responce.data.length === 0 || undefined ? 0 : responce.data.length });
});
}
this.tableHeight();
}
tableHeight() {
var t = window.innerHeight - document.getElementsByClassName('nep-header')[0].clientHeight - 20 + "px"
var ele = document.getElementById("pr");
ele.style.height = t.toString();
}
rowClicked(e) {
setTimeout(() => {
let selectedCompany = this.state.rowData.filter(x => x.cik == e.cik);
selectedCompany = selectedCompany.map(function (obj) {
let val = obj.Companyname;
delete obj['Companyname']
obj.companyname = val;
return obj
}
);
sessionStorage.setItem("selectedCompany", JSON.stringify(selectedCompany));
const { from } = {
from: { pathname: "/company" }
};
this.props.history.push(from);
}, 300)
}
handleClick = (value = this.state.value) => {
value += Math.random() * 12
if (value >= 100) {
value = 100
this.setState({ value })
} else {
this.setState({ value }, () => {
setTimeout(this.handleClick, 320)
})
}
}
render() {
return (
<div id="pr" className="tableSpace">
<label>Companies <span className="tableSpan">({this.state.companyCount})</span></label>
<div style={{ display: (this.showing ? 'block' : 'none') }} >
<Loader />
</div>
<Table
keygen="cik"
striped
bordered
fixed="both"
className="tableClass"
bordered fixed="both"
width={1024}
columns={this.state.columnDefs}
data={this.state.rowData}
onRowClick={this.rowClicked.bind(this)}
/>
<Modal
visible={this.state.visible}
width={500}
title=" Delete Company"
onClose={this.handleCancel}
maskCloseAble={false}
footer={[
<Button key="cancel" className="nep-button nep-button-secondary" onClick={this.handleCancel}>
Cancel
</Button>,
<Button key="ok" type="primary" onClick={this.handleOk}>
Delete
</Button>,
]} >
The company <b>{this.DeleteCompStr}</b> will be permanently deleted and this action cannot be undone. <br /> Are you sure you want to proceed ?
</Modal>
</div>
);}}export default Dashboard;`
My dashbord test cases file code:
import React from 'react'
import { render, cleanup } from '#testing-library/react';
import Dashboard from "../Components/Dashboard/Dashboard"
import axios from "axios";
import { shallow } from 'enzyme'
import { Table } from "#maknowledgeservices/neptune";
afterEach(cleanup);
jest.mock('axios');
it("should render initial layout", () => {
const component = shallow(<Dashboard />);
expect(component.getElements()).toMatchSnapshot();
});
it("test to render Dashboard component", async () => {
axios.post.mockResolvedValue({ data: [{ Companyname: "xyz", accurate: "Positive", }], status: 200, statusText: "OK" });
await render(<Dashboard />, Table);
var result = render(<Dashboard />);
expect(result).toBeTruthy();
});

Implementing an online game in react

I wrote a small game in React which consists of three components,
App <= MainInfo <= Game. The essence of the game is to press the START GAME button and quickly click on all the blue cubes that disappear after clicking. At the end, an alert window pops up with the time and number of cubes pressed, but there are bugs:
After loading, you can click on the blue cubes and they will disappear without pressing START GAME. (So you can even win the game with a zero time counter).
If you press START GAME a couple of times in a row, the counter is accelerated, and after winning, if you press the button, the time continues.
How to make a REFRESH button to restart the game after winning and not reload the entire page?
Link to game - https://quintis1212.github.io/react-game/build/index.html
import React from 'react';
import './App.css';
import MainInfo from './GameContent/MainInfo';
function App() {
return (
<div className="App">
<MainInfo />
</div>
);
}
export default App;
import React, {Component} from 'react';
import Game from './GameTable/Game';
class MainInfo extends Component {
state = {
count:0,
timer:0,
initGame: false
}
shouldComponentUpdate(){
return this.state.initGame;
}
logToConsole = (e)=> {
if (e.target.className === 'Element') {
this.setState((state)=>{
return {count: state.count + 1}
});
e.target.className = 'Element-empty';
console.log(e.target.className)
}
}
timerUpdated(){ this.setState((state)=>{
return {timer: state.timer + 1}
}); }
initGameHandler =()=>{
this.setState({initGame: true})
console.log('refreshHandler')
this.timerID=setInterval(() => { this.timerUpdated() }, 1000);
}
finishGameHandler = (score)=>{
console.log(score)
if(this.state.count === score-1) {
alert('-----GAME OVER-----'+
'YOUR TIME: '+this.state.timer+'seconds'+
' YOUR COUNT: '+this.state.count+'points');
clearInterval(this.timerID)
this.setState({initGame: false})
}
}
render(){
return(
<div>
<p>Timer : <strong>{this.state.timer} seconds </strong></p>
<p>Counter :<strong>{this.state.count}</strong></p>
<button onClick={this.initGameHandler}>START GAME</button>
<Game click={this.logToConsole} updateData={this.finishGameHandler} />
</div>
)
}
}
export default MainInfo;
import React,{Component} from 'react';
class Game extends Component {
shouldComponentUpdate(){
return false
}
render() {
let item;
let count = 0;
let arr = [];
for (let i = 0; i < 70; i++) {
arr.push(Math.floor(Math.random() * 10));
}
item = arr.map((el,i,arr) => {
count++
return el < 2 ? arr[i-1] < 4?<div key={count} className='Element-empty'></div>:<div onClick={(e)=>{this.props.click(e)}} key={count} className='Element'></div> : <div key={count} className='Element-empty'></div>
})
// console.log(item.filter(el => el.props.className == 'Element'))
let score = item.filter(el => el.props.className === 'Element')
let scoreLenhgth=score.length
return(
<div onClick={() => { this.props.updateData(scoreLenhgth)}} >
{item}
</div>
)
}
}
export default Game;
I made quite some changes but got it all to work, didn't put any comments on the changes so please comment if you have any questions.
function App() {
return (
<div className="App">
<MainInfo />
</div>
);
}
class MainInfo extends React.Component {
state = {
count: 0,
timer: 0,
initGame: false,
};
timerUpdated() {
this.setState(state => {
return { timer: state.timer + 1 };
});
}
initGameHandler = () => {
this.setState({ initGame: true });
this.timerID = setInterval(() => {
this.timerUpdated();
}, 1000);
};
gameClickHandler = (correct, itemsLeft) => {
this.setState(
{
count: this.state.count + (correct ? 1 : 0),
},
() => {
if (itemsLeft === 0 || !correct) {
alert(
'-----GAME OVER-----' +
'YOUR TIME: ' +
this.state.timer +
' seconds ' +
' YOUR COUNT: ' +
this.state.count +
' points'
);
clearInterval(this.timerID);
this.setState({
initGame: false,
count: 0,
timer: 0,
});
}
}
);
};
render() {
return (
<div>
<p>
Timer :{' '}
<strong>{this.state.timer} seconds </strong>
</p>
<p>
Counter :<strong>{this.state.count}</strong>
</p>
{this.state.initGame || (
<button onClick={this.initGameHandler}>
START GAME
</button>
)}
{this.state.initGame && (
<Game
click={this.logToConsole}
updateData={this.gameClickHandler}
blocks={2}
/>
)}
</div>
);
}
}
const shuffle = array => {
const copy = [...array];
for (let i = copy.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[copy[i], copy[j]] = [copy[j], copy[i]];
}
return copy;
};
class Game extends React.PureComponent {
constructor(props) {
super(props);
this.state = this.setGame();
}
setGame = () => {
const arr = shuffle(
[...new Array(70)].map((_, i) => i)
);
const selected = arr.slice(0, this.props.blocks || 5);
return { arr, selected };
};
render() {
return (
<div
onClick={e => {
const itemClicked = Number(
e.target.getAttribute('data-id')
);
const correct = this.state.selected.includes(
itemClicked
);
this.props.updateData(
correct,
this.state.selected.length - (correct ? 1 : 0)
);
this.setState(state => ({
selected: state.selected.filter(
v => v !== itemClicked
),
}));
}}
>
{this.state.arr.map((_, i) => (
<div
key={i}
data-id={i}
className={
!this.state.selected.includes(i)
? 'Element-empty'
: 'Element'
}
></div>
))}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
.App {
text-align: center;
}
.Element {
display: inline-block;
width: 40px;
height: 40px;
background-color: cornflowerblue;
border: 2px solid rgb(68, 209, 179);
}
.Element-empty {
display: inline-block;
width: 40px;
height: 40px;
background-color: rgba(158, 147, 100, 0.394);
border: 2px solid rgb(68, 209, 179);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Reactjs Search after onChange

I have implemented a little search functionality in my reactjs application.
The Problem is, that my "searchHandler" function is triggered after every single letter the user enters in the textfield... So e.g. for the term "Lorem" my function is fetching 5 times from my api :(
How can I solve this problem?
Here is my code:
const { scaleDown } = transitions;
function searchingFor(term){
return function(x){
return x.title.toLowerCase().includes(term.toLowerCase()) ||
x.body.toLowerCase().includes(term.toLowerCase());
}
}
class ViewAll extends React.Component{
constructor(props){
super(props);
this.state = {
term: '',
mounted: true,
tracks: [],
hasMoreItems: true,
page: 2,
}
this.searchHandler = this.searchHandler.bind(this);
this.focus = this.focus.bind(this);
this.keyPress = this.keyPress.bind(this);
}
loadContent() {
var requestUrl = this.props.url;
fetch(requestUrl + this.state.page + '&_limit=3').then((response)=>{
return response.json();
}) .then((tracks)=>{
this.setState({ tracks: this.state.tracks.concat(tracks)});
this.setState({page: this.state.page + 1});
if(this.state.page === 6){
this.setState({hasMoreItems: false})
}
}).catch((err)=>{
console.log("There has been an error");
});
}
componentDidMount() {
window.scrollTo(0, 0);
var requestUrl = this.props.url;
fetch(requestUrl + '1&_limit=3')
.then((response)=>{
return response.json();
}) .then((data)=>{
this.setState({tracks : data});
})
.catch((err)=>{
console.log("There has been an error");
});
//this.focus();
}
searchHandler(event){
this.setState({term: event.target.value});
var requestUrl = 'https://questdb.herokuapp.com/all?q='
fetch(requestUrl + this.state.term).then((response)=>{
return response.json();
}) .then((tracks)=>{
this.setState({ tracks: this.state.tracks.concat(tracks)});
}).catch((err)=>{
console.log("There has been an error");
});
}
focus() {
this.textInput.focus();
}
keyPress(e){
if(e.keyCode == 13){
console.log('value', e.target.value);
// put the login here
}
}
render() {
const {term, data, tracks} = this.state;
const loader = <div className="loader2"> </div>;
var items = [];
const imageUrl = require(`../assets/Book.jpg`)
tracks.filter(searchingFor(term)).map(function(title, i)
{
items.push(
<div>
<MuiThemeProvider>
<Paper style={{ borderRadius: "2em",
background: '#ffffff'
}} zDepth={1} >
<ItemViewAll
key={title.id}
/>
</Paper>
</MuiThemeProvider>
</div>
);
}, this);
return (
<div>
<Fade in={true} timeout={1000}>
<div >
<MuiThemeProvider>
<TextField hintText='Bot suchen...'
type="Text"
onChange={this.searchHandler}
value={term}
underlineFocusStyle={{borderColor: '#B00020', borderWidth: 3}}
underlineStyle={{borderColor: '#B00020', borderWidth: 1.5, top: '45px'}}
hintStyle={{fontSize: '8.1vw', fontFamily: 'Anton', color: 'rgba(255,255,255,0.9)'}}
inputStyle={{fontSize: '8.1vw', fontFamily: 'Anton', color: '#ffffff'}}
ref={(input) => { this.textInput = input; }}
style={{caretColor: '#ffffff', width: '90%', maginLeft: 'auto', marginRight: 'auto', marginTop: '12%' }}
InputLabelProps={{ shrink: true }}
/>
</MuiThemeProvider>
</div>
</Fade>
<InfiniteScroll
pageStart={1}
loadMore={this.loadContent.bind(this)}
hasMore={this.state.hasMoreItems}
initialLoad={true}
>
{items}
</InfiniteScroll>
</div>
)
}
}
export default ViewAll;
Here you can check out the Website with the broken search function. As you can see the items are shown double or even triple... After the textfield is emptied, the search results should be removed and only the normal fetched ones should be shown.
https://www.genko.de (use the mobile version in chrome)
Thank you :)
Use lodash debounce. It is used for this exact use case
https://stackoverflow.com/questions/48046061/using-lodash-debounce-in-react-to-prevent-requesting-data-as-long-as-the-user-is
Sample:
import React, {Component} from 'react'
import { debounce } from 'lodash'
class TableSearch extends Component {
//********************************************/
constructor(props){
super(props)
this.state = {
value: props.value
}
this.changeSearch = debounce(this.props.changeSearch, 250)
}
//********************************************/
handleChange = (e) => {
const val = e.target.value
this.setState({ value: val }, () => {
this.changeSearch(val)
})
}
//********************************************/
render() {
return (
<input
onChange = {this.handleChange}
value = {this.props.value}
/>
)
}
//********************************************/
}
If you don't need full lodash package you can write it yourself:
function debounce(f, ms) {
let timer = null;
return function (...args) {
const onComplete = () => {
f.apply(this, args);
timer = null;
}
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(onComplete, ms);
};
}
The first arg (f) is your function which should not be performed more often than
second arg (ms) - amount of ms ). So in your case you can write your handler in next way:
handleChange = debounce((e) => {
const val = e.target.value
this.setState({ value: val }, () => {
this.changeSearch(val)
})
}, 1000) // second arg (1000) is your amount of ms

Decrement and increment quantity with Reactjs

I am newbie to Reactjs and I am making a function to increase and decrease quantity. My code below:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
quantity: 1,
show: true,
max:5,
min:0
};
}
IncrementItem = () => {
if(this.state.quantity > 9) {
}else {
this.setState({
quantity: this.state.quantity + 1
});
}
}
DecreaseItem = () => {
if(this.state.quantity <= 1) {
}else {
this.setState({ quantiy: this.state.quantity - 1 });
}
}
ToggleClick = () => {
this.setState({ show: !this.state.show });
}
render() {
return (
<div>
<button onClick={this.IncrementItem}>+</button>
<input className="inputne" value={this.state.quantity} />
<button onClick={this.DecreaseItem}>-</button>
</div>
);
}
I have problems are:
Browser appears an error :
Warning: Failed prop type: You provided a value prop to a form field without an onChange handler
I cannot change value in input from View.
Please let me know how to solve. Thank for your help.
There are two issues in this code:
There is no onChange handler. Read more on how to handle onChange listeners here
Using value from this.state.quantity to increment and decrement is bad practice because setState function is asynchronous.
You can use functional version of setState to get around this:
this.setState(prevState => {
if(prevState.quantity > 0) {
return {
quantity: prevState.quantity - 1
}
} else {
return null;
}
});
Code Snippet:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
quantity: 1,
show: true,
max: 5,
min: 0
};
}
IncrementItem = () => {
this.setState(prevState => {
if(prevState.quantity < 9) {
return {
quantity: prevState.quantity + 1
}
} else {
return null;
}
});
}
DecreaseItem = () => {
this.setState(prevState => {
if(prevState.quantity > 0) {
return {
quantity: prevState.quantity - 1
}
} else {
return null;
}
});
}
ToggleClick = () => {
this.setState({
show: !this.state.show
});
}
handleChange = (event) => {
this.setState({quantity: event.target.value});
}
render() {
return ( <div>
<button onClick={this.IncrementItem}>+</button>
<input className="inputne" value={this.state.quantity} onChange={this.handleChange}/>
<button onClick = {this.DecreaseItem}>-< /button>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
You need to Update the value, add a onChange on Input field to do that.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
quantity: 1,
show: true,
max:5,
min:0
};
}
IncrementItem = () => {
if(this.state.quantity > 9) {
}else {
this.setState({
quantity: this.state.quantity + 1
});
}
}
DecreaseItem = () => {
if(this.state.quantity <= 1) {
}else {
this.setState({ clicks: this.state.quantity - 1 });
}
}
ToggleClick = () => {
this.setState({ show: !this.state.show });
}
UpdateValue = (e) => {
this.setState({ quantity: e.target.value });
}
render() {
return (
<div>
<button onClick={this.IncrementItem}>+</button>
<input className="inputne" value={this.state.quantity} onChange={this.UpdateValue} />
<button onClick={this.DecreaseItem}>-</button>
</div>
);
}
Try this as well it may help you
class Counters extends Component {
state = {
counters: [
{ id: 1, value: 4, max: 15, min: 0, show: true },
{ id: 2, value: 0 }`enter code here`
]
};
handleIncrement = counter => {
const counters = [...this.state.counters];
const index = counters.indexOf(counter);
if (counters[index].value < counters[index].max) {
counters[index].value++;
}
this.setState({ counters });
};
handleDecrement = counter => {
const counters = [...this.state.counters];
const index = counters.indexOf(counter);
if (counters[index].value > counters[index].min) {
counters[index].value--;
}
this.setState({ counters });
};
handleDelete = counterId => {
const counters = this.state.counters.filter(c => c.id !== counterId);
this.setState({ counters });
};
render() {
return (
<div>
{this.state.counters.map(counter => (
<Counter
key={counter.id}
onDelete={this.handleDelete}
onIncrement={this.handleIncrement}
onDecrement={this.handleDecrement}
counter={counter}
/>
))}
</div>
);
}
}
export default Counters;
enter code here

Resources