My forEach statement is repeating more than it should - javascript

I am using firebase and react js. my forEach loop is only supposed to repeat for the number of objects I have stored in the firebase database but instead of repeated the expected 3 times it will repeat 8 or 9 or something like that. Also when I run the code a second time it will repeat super fast and fill up my console.
constructor() {
super()
this.state = {
warmupList: [],
title: "",
id: ""
}
}
handleInputChange = (e) => {
this.setState({
title: e.target.value
})
}
SetActiveWarmup(id) {
const warmupRef = firebase.database().ref("Warmups")
warmupRef.on("value",(snapshot) => {
const warmups = snapshot.val()
this is where the for each is
Object.keys(warmups).forEach(key => {
if(id === key) {
warmupRef.child(key).update({
activity: "True"
})
} else {
warmupRef.child(key).update({
activity: "False"
})
}
console.log("has run")
})
})
}
createWarmup = (e) => {
e.preventDefault()
if(this.state.title === "") return
const warmupRef = firebase.database().ref("Warmups")
var key = warmupRef.push().key
warmupRef.child(key).set({
title: this.state.title,
activity: "True",
id: key
})
this.setState({
title: ""
})
}
componentWillMount() {
this._isMounted = true;
const warmupRef = firebase.database().ref("Warmups")
warmupRef.on("value",(snapshot) => {
const warmups = snapshot.val()
const warmupList = []
for(let id in warmups) {
warmupList.push(warmups[id])
}
this.setState({
warmupList: warmupList
})
})
}
render() {
return (
<div className={`warmup${this.props.activity}`}>
<div className="newWarmup__bottom">
<form onSubmit={this.createWarmup}>
<input placeholder="My Warmup..."
value={this.state.title}
onChange={this.handleInputChange} />
<CircleButton click={this.createWarmup}
Icon={AddIcon} color="Green" />
</form>
</div>
<div className="warmup__select">
{this.state.warmupList.map(warmup =>
<SelectWarmup key={v4()}
text={warmup.title}
activity={warmup.activity}
click={() => this.SetActiveWarmup(warmup.id)} />
)}
</div>
</div>
)
}
}

Related

State won't update

I'm working on order system for my portfolio and I need your help.
for some reason one of the state values won't update while other does.
state = {
currOrder: {
createdAt: Date.now(),
totalPrice: 0,
lastUpdated: Date.now(),
notes: '',
products: [],
miniClient: {
_id: '',
fullName: ''
}
},
client: this.props.client
}
componentDidMount() {
if (this.props.currOrder) {
const currOrder = this.props.currOrder
this.setState({ currOrder })
} else {
this.setState({ currOrder: { ...this.state.currOrder, miniClient: { _id: this.state.client._id, fullName: this.state.client.fullName } } })
}
}
onHandleChange = (ev) => {
if (ev.target) {
const { target } = ev
const field = target.name
const value = target.type === 'number' ? +target.value : target.value
this.setState((prevState) => ({ currOrder: { ...prevState.currOrder, [field]: value } }))
}
}
getOrderLastUpdate = () => {
const updateDate = Date.now()
this.setState({ currOrder: { ...this.state.currOrder, lastUpdated: updateDate } }, () => { console.log(this.state.currOrder) })
}
onSubmitOrder = () => {
const { currOrder } = this.state
if (!currOrder._id) {
this.props.addOrder(currOrder)
this.props.isEditModalOpen()
} else {
this.getOrderLastUpdate()
this.props.updateOrder(currOrder)
this.props.isEditModalOpen()
}
}
render() {
const { notes, totalPrice, lastUpdated } = this.state.currOrder
const { client } = this.props
return (
<div className="order-edit">
<div>{client.fullName}</div>
<div>{utilService.formattedDates(lastUpdated)} : עודכן לאחרונה</div>
<div className="order-edit-info-holder">
<input type="number"
name="totalPrice"
value={totalPrice}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">מחיר</label>
</div>
<div className="order-edit-info-holder">
<input type="text"
name="notes"
value={notes}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">הערות</label>
</div>
<div className="order-edit-btns-container">
<button onClick={this.onSubmitOrder}>שמור</button>
<button onClick={this.props.isEditModalOpen}>בטל</button>
</div>
</div>
)
}
for some reason it refuses to update the lastUpdated value (as all other values are working fine :-()
Am I doing something wrong?
as for now the CB for getOrderLastUpdate function (console.log) won't even work.

Reset table using reset button

I'm new React developer(mainly with hooks but did not find good example with hooks), here i have antd table with search functionality, my question is when user writes something in search then user gets different result, how to cancel that search by clicking 'Reset' button ?
my code:
https://codesandbox.io/s/antd-table-filter-search-forked-mqhcn?file=/src/EventsSection/EventsSection.js
You can add an id to your input into TitleSearch.js:
<Search
id='IDYOUWANT'
placeholder="Enter Title"
onSearch={onSearch}
onChange={onChange}
style={{ width: 200 }}
/>
And add event into EventsSection.js
ResetInput = () => {
const input = document.getElementById('IDYOUWANT');
input.value = '';
this.handleSearch('');
}
....
<button
onClick={this.ResetInput}
>Reset</button>
Change IDYOUWANT with your id
run this code
Created a new function for reset value and trigger it from reset button.
function:
resetValue = () =>{
this.setState({
eventsData: eventsData
});
}
And trigger from button
<button onClick={this.resetValue}>Reset</button>
all code::
import React, { Component } from "react";
import styles from "./style.module.css";
import { EventsTable } from "../EventsTable";
import { StatusFilter } from "../StatusFilter";
import { TitleSearch } from "../TitleSearch";
const eventsData = [
{
key: 1,
title: "Bulletproof EP1",
fileType: "Atmos",
process: "match media",
performedBy: "Denise Etridge",
operationNote: "-",
updatedAt: "26/09/2018 17:21",
status: "complete"
},
{
key: 2,
title: "Dexter EP2",
fileType: "Video",
process: "Compliance",
performedBy: "Dane Gill",
operationNote: "passed",
updatedAt: "21/09/2018 12:21",
status: "inProgress"
}
];
class EventsSection extends Component {
constructor(props) {
super(props);
this.state = {
eventsData
};
}
handleFilter = (key) => {
const selected = parseInt(key);
if (selected === 3) {
return this.setState({
eventsData
});
}
const statusMap = {
1: "complete",
2: "inProgress"
};
const selectedStatus = statusMap[selected];
const filteredEvents = eventsData.filter(
({ status }) => status === selectedStatus
);
this.setState({
eventsData: filteredEvents
});
};
handleSearch = (searchText) => {
const filteredEvents = eventsData.filter(({ title }) => {
title = title.toLowerCase();
return title.includes(searchText);
});
this.setState({
eventsData: filteredEvents
});
};
handleChange = (e) => {
const searchText = e.target.value;
const filteredEvents = eventsData.filter(({ title }) => {
title = title.toLowerCase();
return title.includes(searchText);
});
this.setState({
eventsData: filteredEvents
});
};
resetValue = () =>{
this.setState({
eventsData: eventsData
});
}
render() {
return (
<section className={styles.container}>
<header className={styles.header}>
<h1 className={styles.title}>Events</h1>
<button onClick={this.resetValue}>Reset</button>
<TitleSearch
onSearch={this.handleSearch}
onChange={this.handleChange}
className={styles.action}
/>
</header>
<EventsTable eventsData={this.state.eventsData} />
</section>
);
}
}
export { EventsSection };
Here is what i did in order to solve it:
i added onClick on the button
<button onClick={this.resetSearch}>Reset</button>
Then in the function i put handleSearch to '', by doing this it reset the table:
resetSearch = () =>{
this.handleSearch('')
}

Set initial class variable from axios request in React

When i call this function
getQuestions = () => {
this.setState({ loading: true })
const { data } = this.props
axios
.get(data.questions)
.then((res) => {
this.setState({
loading: false,
questions: res.data,
})
this.initialQuestions = res.data
})
.catch((err) =>
this.setState({
loading: false,
questions: [],
})
)
}
it updates the array questions in state and array initialQuestions variable in constructor. The state questions represents the values form inputs. The inputs are handled in child component with this code
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions[e.target.getAttribute('data-id')][e.target.name] =
e.target.value
setQuestions(questions)
}
setQuestions is passed in props as setQuestions={(state) => this.setState({ questions: state })}
So when i change the value of inputs the onChange function is called and it changes the parent component questions in state. But the parent variable this.initialQuestions also is being changed to the questions value from state, but I don't know why
Edit:
That's the code you should be able to run
const { Component } = React;
const Textarea = "textarea";
const objectsEquals = (obj1, obj2) =>
Object.keys(obj1).length === Object.keys(obj2).length &&
Object.keys(obj1).every((p) => obj1[p] === obj2[p])
class QuestionList extends React.Component {
static propTypes = {
questions: PropTypes.array,
removeQuestion: PropTypes.func.isRequired,
hasChanged: PropTypes.func.isRequired,
setQuestions: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.questions = props.questions
this.onChange = this.onChange.bind(this)
}
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions[e.target.getAttribute('data-id')][e.target.name] =
e.target.value
setQuestions(questions)
if (hasChanged && this.questions.length > 0) {
// array of booleans, true if object has change otherwise false
const hasChangedArray = this.props.questions.map(
(_, index) =>
!objectsEquals(
this.questions[index],
this.props.questions[index]
)
)
console.log("hasChangedArray = ", hasChangedArray)
console.log("this.questions[0] = ", this.questions[0])
console.log("this.props.questions[0] = ", this.props.questions[0])
// If true in array than the form has changed
hasChanged(
hasChangedArray.some((hasChanged) => hasChanged === true)
)
}
}
render() {
const { removeQuestion, questions } = this.props
const questionList = questions.map((question, index) => (
<div className="card" key={index}>
<div className="card__body">
<div className="row">
<div className="col-sm-7">
<div className="form-control">
<label className="form-control__label">
Question:
</label>
<input
type="text"
id={`question-${index}`}
data-id={index}
onChange={this.onChange}
name="question"
value={
this.props.questions[index].question
}
className="form-control__input form control__textarea"
placeholder="Pass the question..."
rows="3"
/>
</div>
<div className="form-control">
<label className="form-control__label">
Summery:
</label>
<Textarea
id={`summery-${index}`}
data-id={index}
onChange={this.onChange}
name="summery"
value={this.props.questions[index].summery}
className="form-control__input form-control__textarea"
placeholder="Pass the summery..."
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
))
return questionList
}
}
class Questions extends React.Component {
constructor(props) {
super(props)
this.initialQuestions = []
this.state = {
loading: true,
questions: [],
hasChanged: false,
}
this.getQuestions = this.getQuestions.bind(this)
this.resetForm = this.resetForm.bind(this)
}
resetForm = () => {
console.log("this.initialQuestions =", this.initialQuestions)
this.setState({
questions: this.initialQuestions,
hasChanged: false,
})
}
getQuestions = () => {
this.setState({ loading: true })
const { data } = this.props
// axios
// .get(data.questions)
// .then((res) => {
// this.setState({
// loading: false,
// questions: res.data,
// })
// this.initialQuestions = res.data
// })
// .catch((err) =>
// this.setState({
// loading: false,
// questions: [],
// })
// )
// You can't do a database request so here is some example code
this.setState({
loading: false,
questions: [
{
question: 'example-question',
summery: 'example-summery',
},
{
question: 'example-question-2',
summery: 'example-summery-2',
},
],
})
this.initialQuestions = [
{
question: 'example-question',
summery: 'example-summery',
},
{
question: 'example-question-2',
summery: 'example-summery-2',
},
]
}
componentDidMount = () => this.getQuestions()
render() {
const { loading, questions, hasChanged } = this.state
if (loading) return <h1>Loading...</h1>
return (
<form>
<QuestionList
questions={questions}
hasChanged={(state) =>
this.setState({ hasChanged: state })
}
setQuestions={(state) =>
this.setState({ questions: state })
}
/>
<button
type="reset"
onClick={this.resetForm}
className={`btn ${
!hasChanged
? 'btn__disabled'
: ''
}`}
>
Cancel
</button>
<button
type="submit"
className={`btn btn__contrast ${
!hasChanged
? 'btn__disabled'
: ''
}`}
>
Save
</button>
</form>
)
}
}
ReactDOM.render(<Questions />, document.querySelector("#root"));
<script src="https://unpkg.com/react#17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types#15/prop-types.min.js"></script>
<div id="root"></div>
Both state questions and class variable initialQuestions hold reference of res.data. Now when you update questions in onChange method, you are updating it by reference i.e directly mutating it and hence the class variable is also updated
You must not update it by reference but clone and update like below
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions = questions.map((question, idx) => {
if(idx === e.target.getAttribute('data-id')) {
return {
...question,
[e.target.name]: e.target.value
}
}
return question;
});
setQuestions(questions)
}

Why isn't the map function iterating over the array?

I am using React, which I am new to and it says to use the map method to iterate over the array. When I do that the entire array logs to the console and not the individual words I want.
I am trying to call stock symbols when a user types them in the text box. But under the function getSymbol() the state of symbol is still an array even when I used map in render. Can anyone point me in the right direction? Or what can I do to get single elements.
Here is my code:
class Symbol extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: '',
symbol: [],
isLoaded: false
}
}
typeSymbol = (e) => {
this.setState({
userInput: e.target.value.toUpperCase()
}, () => {
console.log(this.state.userInput)
})
}
getSymbol = (e) => {
e.preventDefault(),
this.setState({
symbol: this.state.symbol
}, () => {
console.log(this.state.symbol)
})
}
componentDidMount() {
fetch(`https://finnhub.io/api/v1/stock/symbol?exchange=US&token=${key}`)
.then(res => res.json())
.then(
(results) => {
this.setState({
isLoaded: true,
symbol: results
});
// console.log(this.state.symbol)
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { symbol, userInput } = this.state
if (userInput === symbol) {
return (
symbol.map((symbol, i) => (<span className="symbol" key={i}>{symbol.displaySymbol}</span>)),
console.log('same')
)
} else {
return (
<div className="enterstock">
<h1 className="title">Enter Stock Symbol</h1>
<form className="inputfields" onSubmit={this.getSymbol}>
<input type="text" className="symfields" name="symbolname" onChange={this.typeSymbol}></input>
<button type="submit" className="btn">Send</button>
</form>
</div >
)
}
}
}
You're using symbol in two different ways, and they're colliding. Try renaming the parameter of your map() function:
symbol.map((s, i) => (<span className="symbol" key={i}>{s.displaySymbol}</span>)),
symbol is not a reserved word in JavaScript, so you should be good there.
The problem is with your if block. The map method works fine. What is happening is you are comparing the userInput(String) to symbol(an array) it will not work. I don't know what check you're trying to do. But if it is to check whether the userInput is in the array you're doing it wrongly.
import React from "react";
class Symbol extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: "",
symbol: [],
isFiltered: false,
isLoaded: false,
};
}
typeSymbol = (e) => {
this.setState(
{
userInput: e.target.value.toUpperCase(),
},
() => {
console.log(this.state.userInput);
}
);
};
getSymbol = (e) => {
e.preventDefault();
const filter = this.state.symbol.filter(
(el) => el.displaySymbol === this.state.userInput
);
// console.log(filter);
this.setState(
{
symbol: filter,
isFiltered: true,
},
() => {
console.log(this.state.symbol);
}
);
};
componentDidMount() {
fetch(`https://finnhub.io/api/v1/stock/symbolexchange=US&token=${key}`)
.then((res) => res.json())
.then(
(results) => {
this.setState({
isLoaded: true,
symbol: results,
});
console.log(this.state.symbol);
},
(error) => {
this.setState({
isLoaded: true,
error,
});
}
);
}
render() {
const { symbol, userInput } = this.state;
//console.log(userInput);
if (this.state.isFiltered) {
return symbol.map((symbol, i) => {
return (
<span className="symbol" key={i}>
{symbol.displaySymbol}
</span>
);
});
} else {
return (
<div className="enterstock">
<h1 className="title">Enter Stock Symbol</h1>
<form className="inputfields" onSubmit={this.getSymbol}>
<input
type="text"
className="symfields"
name="symbolname"
onChange={this.typeSymbol}
></input>
<button type="submit" className="btn">
Send
</button>
</form>
</div>
);
}
}
}
export default Symbol;

Cannot delete input content in Typeahead react-bootstrap

Trying to delete the contents of the input field by pressing backspace. However, nothing can be deleted. When I delete onChange = {this.handleSelectContractor} the field can be cleared, but after adding onChange = {this.handleSelectContractor} nothing can be done.
Pass selected todo to the handleSelect and assign it to the variable selected. The variable selected should appear in the input field
Demo here: https://stackblitz.com/edit/react-agfvwn?file=index.js
class App extends Component {
constructor() {
super();
this.state = {
todos: [],
selected: [],
todo: {},
todo2: 'ddd'
};
}
componentDidMount() {
this.getTodos().then(() => {
const todo = this.state.todos.find(todo => todo.id === 4);
this.setState({
selected: todo ? [todo] : []
})
})
}
getTodos = () => {
return axios({
url: 'https://jsonplaceholder.typicode.com/todos',
method: "GET"
})
.then(res => {
this.setState({
todos: res.data
});
})
.catch(error => {
console.log(error);
})
}
handleSelect = (todo) => {
let newArray = [...this.state.selected];
newArray.push(todo)
if(todo) {
this.setState({
todo: newArray
})
} else {
this.setState({
todo2: ''
})
}
}
render() {
console.log(this.state.todo)
return (
<div>
<Typeahead
id={'sasas'}
selected={this.state.selected}
labelKey="title"
onChange={this.handleSelect}
options={this.state.todos}
ref={(ref) => this._typeahead = ref}
/>
</div>
);
}

Categories

Resources