React: TodoList: Give an Input to an Array - reactjs

I am currently working on a React Todo app. I'm still a React beginner, I've watched all kinds of tutorials but I can't find a solution to my problem.
I'm trying to process the text field (describtion) so that it creates a new array Element.
I pass the describtion into the function createTodo. There, a new object is created that contains the describtion and an id. This object is then pushed into the array TODOS.
My problem is that the describtion is undefined every time.
Please help and thank you:)
Translated with www.DeepL.com/Translator (free version)
import React from 'react';
import ReactDOM from 'react-dom';
class TodoTable extends React.Component {
constructor(props){
super(props);
this.state = {
enterTodo: '',
status: false
}
this.handleEnterTodo = this.handleEnterTodo.bind(this);
this.handleStatus = this.handleStatus.bind(this);
this.createTodo = this.createTodo.bind(this);
}
handleEnterTodo(event){
this.setState({
enterTodo: this.props.value
});
}
handleStatus(event){
this.setState({
status: this.props.true
});
}
createTodo(event){
const todo = {
id: 5,
describtion: this.props.enterTodo
}
TODOS.push(todo);
console.log(this.props.enterTodo);
}
render(){
const todos = this.props.todos;
//Gibt handleListener Funktionen an Child Komponente als Props weiter
return(
<>
<InputBar createTodo={this.createTodo} handleEnterTodo={this.handleEnterTodo} enterTodo={this.state.enterTodo}/>
<Todo handleStatus={this.handleStatus} status={this.state.status} todos={todos} />
</>
);
}
}
class InputBar extends React.Component {
render(){
return(
<form>
<input type='text' placeholder='Type in a Note'
value={this.props.enterTodo}
onChange= { this.props.handleEnterTodo }
/>
<button type='button' onClick={this.props.createTodo}>Enter</button>
<button>Clear Done</button>
</form>
);
}
}
class Todo extends React.Component {
render(){
const todoList = [];
this.props.todos.forEach((element, index) => {
let todo = <div><form>{this.props.todos[index].describtion}<input type='checkbox' checked={this.props.status} onChange={this.props.handleStatus} /></form></div>;
todoList.push(todo);
})
return(
todoList
);
}
}
//Mockdaten
let TODOS = [
{
id: 0,
describtion: 'Work more',
status: 'open'
},
{
id: 1,
describtion: 'Sleep more',
status: 'open'
},
{
id: 2,
describtion: 'Drink less',
status: 'done'
},
{
id: 3,
describtion: 'Learn more',
status: 'done'
},
];
//Render App
ReactDOM.render(
<TodoTable todos={TODOS} />,
document.getElementById('root')
);

Try this approach,
import "./styles.css";
import React from "react";
let TODOS = [
{
id: 0,
describtion: "Work more",
status: "open"
},
{
id: 1,
describtion: "Sleep more",
status: "open"
},
{
id: 2,
describtion: "Drink less",
status: "done"
},
{
id: 3,
describtion: "Learn more",
status: "done"
}
];
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<TodoTable todos={TODOS} />
</div>
);
}
class TodoTable extends React.Component {
constructor(props) {
super(props);
this.state = {
enterTodo: "",
todos: this.props.todos,
status: false
};
this.handleEnterTodo = this.handleEnterTodo.bind(this);
this.handleStatus = this.handleStatus.bind(this);
this.createTodo = this.createTodo.bind(this);
}
handleEnterTodo(event) {
this.setState({
enterTodo: event.target.value
});
}
handleStatus(event) {
this.setState({
status: this.props.true
});
}
createTodo(event) {
const todo = {
id: 5,
describtion: this.state.enterTodo
};
this.setState({
todos: [...this.state.todos, todo]
});
}
render() {
const todos = this.state.todos;
//Gibt handleListener Funktionen an Child Komponente als Props weiter
return (
<>
<InputBar
createTodo={this.createTodo}
handleEnterTodo={this.handleEnterTodo}
enterTodo={this.state.enterTodo}
/>
<Todo
handleStatus={this.handleStatus}
status={this.state.status}
todos={todos}
/>
</>
);
}
}
class InputBar extends React.Component {
render() {
return (
<form>
<input
type="text"
placeholder="Type in a Note"
value={this.props.enterTodo}
onChange={this.props.handleEnterTodo}
/>
<button type="button" onClick={this.props.createTodo}>
Enter
</button>
<button>Clear Done</button>
</form>
);
}
}
class Todo extends React.Component {
render() {
const todoList = [];
this.props.todos.forEach((element, index) => {
let todo = (
<div>
<form>
{this.props.todos[index].describtion}
<input
type="checkbox"
checked={this.props.status}
onChange={this.props.handleStatus}
/>
</form>
</div>
);
todoList.push(todo);
});
return todoList;
}
}
You shouldn't update the props value. instead, create a list in the local state itself. And use the local state value for render the template.
Also, You should access entered description value from the event object like below.
handleEnterTodo(event) {
this.setState({
enterTodo: event.target.value
});
}
codesandbox- https://codesandbox.io/s/compassionate-ride-k5gdus?file=/src/App.js

Related

My checkbox is not changing from check or uncheck, but I can see that state value is changing, what's going on?

So when I run this and check the checkbox, I can see the values changing in the state, but why is the checkbox control not changing its status from check/uncheck? I know the render() method is being hit as well. Why, oh why, Gods of code? Lost in hours of figuring out what's wrong and I'm lost!
bob-Todos.js FILE
class Todo extends React.Component {
constructor(param) {
super();
this.state = {
id: param.data.id,
text: param.data.text,
completed: param.data.completed,
onMyChange: param.OnChange,
};
}
render() {
console.log("In TODO Render");
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
this.state.onMyChange(this.state.id);
}}
checked={this.state.completed}
/>
{this.state.text}
</p>
</div>
);
}
}
export default Todo;
Bob-App.js FILE
import React, { Component } from "react";
import Todo from "./bob-Todo";
import todoData from "../data/bob-todosData";
class App extends Component {
constructor() {
super();
this.state = { data: todoData };
this.OnChange = this.OnChange.bind(this);
}
OnChange(myId) {
this.setState((prev) => {
let updatedTodos = prev.data.map((todo) => {
if (todo.id === myId) {
todo.completed = !todo.completed;
}
return todo;
});
return { data: updatedTodos };
});
console.log(this.state.data);
}
render() {
return this.state.data.map((item) => {
return <Todo key={item.id} data={item} OnChange={this.OnChange} />;
});
}
}
export default App;
bob-todosData.js FILE
const todosData = [
{
id: 1,
text: "take out the trash",
completed: true
},
{
id: 2,
text: "rest for a while and relax",
completed: false
},
{
id: 3,
text: "watch an online movie",
completed: true
}
]
export default todosData
index.js FILE
import React from 'react';
import ReactDOM from 'react-dom';
import AppBob from "./bobComponents/Bob-App";
ReactDOM.render(
<AppBob />, document.getElementById('root')
);
You don't need to assign your props to state in your Todo component
Just remove them and invoke the function also use those variables directly:
Then your component will be:
class Todo extends React.Component {
render() {
const {
data: {
id,
text,
completed,
},
OnChange, // <-- Should rename this to "onChange"
} = this.props;
console.log('In TODO Render');
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
OnChange(id);
}}
checked={completed}
/>
{text}
</p>
</div>
);
}
}
export default Todo;
Also, rename your OnChange function to onChange to enable js convention

'delTodo' is not defined. React (line 51)

Error:
'delTodo' is not defined. React (line 51)
I am new to React. Here is the code; what did I do wrong?
import React, { Component } from 'react';
import Todos from './components/Todos';
import markComplete from './components/Todos'
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{
key: 1,
title: 'Take out the trash',
completed:false
},
{`enter code here`
key: 2,
title: 'Dinner with wife',
completed:true`enter code here`
},
{
key: 3,
title: 'Meeting with boss',
completed:false
}
]
}
}
asd = () =>{
}
// Toggle Complete
markComplete = (key) => {
this.setState({ todos: this.state.todos.map(todo=> {
if(todo.key === key) {
todo.completed = !todo.completed
}
return todo;
}) });
}
//Delete Todo
delTodo = (key) => {
console.log(key)
}
render() {
return (
<div className="App">
<Todos todos={this.state.todos} markComplete={markComplete}
delTodo={delTodo} />
</div>
);
}
}
export default App;
If you're using a class component, you need to use the this keyword when you refer to class attributes (state, methods, etc.). So the method should be this.delTodo:
return (
<div className="App">
<Todos
todos={this.state.todos}
markComplete={this.markComplete}
delTodo={this.delTodo}
/>
</div>
)

How to make an axios POST request in React?

So, some context: Users submit a dog name via a text input, and this is controlled by the 'Dogue.jsx' component:
import React from 'react';
class Dogue extends React.Component {
constructor(props) {
super(props);
this.state = {
id: props.id,
nameInput: '',
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
nameInput: e.target.value,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.inputFunction(this.state.nameInput);
}
render() {
console.log(this.props.id);
return (
<div className="dogue-container">
<img className="img" src={this.props.dogList} />
<br />
<form onSubmit={this.handleSubmit} className="form">
<input
onChange={this.handleChange}
className="input"
type="text"
placeholder="Enter dog name"
/>
<br />
<button className="button">Submit</button>
</form>
<h2 className="text">Name: {this.props.name} </h2>
</div>
);
}
}
export default Dogue;
The submitted information is then passed to 'App.jsx', where it is used to update state:
import React, {Component} from 'react';
import './styles.css';
import DogList from './DogList';
import axios from 'axios';
class App extends React.Component {
constructor() {
super();
this.state = {
loading: false,
dog: [],
dogName: [],
};
this.updateStateWithInput = this.updateStateWithInput.bind(this);
}
setData = async () => {
const x = await fetch('https://dog.ceo/api/breed/hound/images');
const y = await x.json();
const z = await y.message;
let newArr = [];
for (let i = 0; i < z.length; i++) {
if (i <= 9) {
newArr.push(z[i]);
}
}
return newArr;
};
async componentDidMount() {
this.setState({
loading: true,
});
let dogPromise = await this.setData();
let dogNamePromise = await axios.get('http://localhost:3000/dogs');
this.setState({
loading: false,
dog: dogPromise,
dogName: dogNamePromise.data,
});
}
updateStateWithInput(nameInput) {
//Here is where state is updated.
//change state, then use axios.post to submit data
}
render() {
return this.state.loading ? (
<h1 className="text"> Dogues Loading.....</h1>
) : (
<div>
<h1 className="text">Rate My Dogue</h1>
<DogList
dogs={this.state.dog}
name={this.state.dogName}
inputFunction={this.updateStateWithInput}
/>
</div>
);
}
}
export default App;
The updated state, I imagine, will be used in the axios post request to submit data to the database. So, I've got input data being sent from Dogue to App, I'm just not sure what to do now? The information currently in state looks as follows:
[
{
id: 1,
dogName: 'bruce',
},
{
id: 2,
dogName: 'borker',
},
{
id: 3,
dogName: 'henry',
},
];
I should also show my map function, in DogList.jsx:
import React from 'react';
import Dogue from './Dogue';
const DogList = (props) => {
return (
<div className="img-container">
{props.dogs.map((doggie, index) => {
return (
<Dogue
id={props.name[index] && props.name[index].id}
key={index}
dogList={doggie}
name={props.name[index] && props.name[index].dogName}
inputFunction={props.inputFunction}
/>
);
})}
</div>
);
};
export default DogList;
You can send a POST request with axios by calling:
axios.post(url, data, options);
It’s similar to the way you called the get method to make a GET request.
I’m leaving this axios cheat sheet here since it’s really useful until you get the hang of it:
https://kapeli.com/cheat_sheets/Axios.docset/Contents/Resources/Documents/index

Gatsby Stripe Checkout - multiple quantities

I'm following this Gatsby guide - https://www.gatsbyjs.org/tutorial/ecommerce-tutorial/
I would like to modify this code to allow the user to change the number of items they can purchase.
Following this React guide - https://reactjs.org/docs/forms.html - I am adding an <input> field to allow a quantity to be chosen.
I then want to pass the value to here - items: [{ sku: "XXXXXXXX", quantity: 1 }]
The error I get is TypeError: _this.handleInputChange is undefined on the line this.handleInputChange = this.handleInputChange.bind(this);
Any pointers would be great, thanks.
import React from "react"
const Checkout = class extends React.Component {
constructor(props) {
super(props);
this.state = {
numberOfItems: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
componentDidMount() {
this.stripe = window.Stripe("XXXXXXX")
}
async redirectToCheckout(event) {
event.preventDefault()
const { error } = await this.stripe.redirectToCheckout({
items: [{ sku: "XXXXXXXX", quantity: 1 }],
successUrl: `http://localhost:8000/thank-you`,
cancelUrl: `http://localhost:8000/`,
})
if (error) {
console.warn("Error:", error)
}
}
render() {
return (
<div>
<label>
Number to buy
<input
name="numberOfItems"
type="number"
value={this.state.numberOfItems}
onChange={this.handleInputChange} />
</label>
<button
onClick={event => this.redirectToCheckout(event)}
>
Buy Now
</button>
</div>
)
}
}
export default Checkout
Update: I went with a different solution in the end:
import React from "react"
const Checkout = class extends React.Component {
state = { count: 1 }
handleIncrement = () => {
this.setState({ count: this.state.count + 1 })
}
handleDecrement = () => {
if(this.state.count > 1){
this.setState({ count: this.state.count - 1 })
}
}
componentDidMount() {
this.stripe = window.Stripe("")
}
async redirectToCheckout(event) {
event.preventDefault()
const { error } = await this.stripe.redirectToCheckout({
items: [{ sku: "", quantity: this.state.count }],
successUrl: `http://localhost:8000/thank-you`,
cancelUrl: `http://localhost:8000/`,
})
if (error) {
console.warn("Error:", error)
}
}
render() {
return (
<div>
<button onClick={this.handleIncrement}>+</button>
<div>
{this.state.count}
</div>
<button onClick={this.handleDecrement}>-</button>
<button
onClick={event => this.redirectToCheckout(event)}
>
Buy
</button>
</div>
)
}
}
export default Checkout
There is no such function handleInputChange in your class.
I believe you forgot to implement it in your class, for example:
import React from 'react';
const Checkout = class extends React.Component {
constructor(props) {
super(props);
this.state = {
numberOfItems: 2,
inputValue
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(e) {
this.setState({ inputValue: e.target.value });
}
render() {
return (
<div>
<label>
Number to buy
<input
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
</label>
</div>
);
}

Error: Super expression must either be null or a function

Problem
So as the title said i've this issue in a todoapp. i checked if i had some typo like react instead of React and it seems to be alright.
Before post something i checked:
First post stackoverflow
Second post stackoverflow
but i cannot find a solution
Code
App.js
import React, {Component} from 'react';
import Form from './Components/Form';
import Footer from './Components/Footer';
import Header from './Components/Header';
class App extends React{
constructor(props) {
this.state = {
todoValue: "",
filterType: "All",
todos: [],
}
}
handleChange = (event) => {
this.setState({
todoValue: event.target.value,
})
}
handleClick = (event) => {
event.preventDefault();
if (this.state.todoValue !== "") {
const todo = {
id: Date.now(),
text: this.state.todoValue,
done: false,
}
this.setState({
todoValue: "",
todos: [todo, ...this.state.todos],
})
}
}
handleToggle = (id) => {
this.setState((prevState) => {
return {
todos: prevState.todos.map((item, i) => {
if (item.id === id) {
return {
...item,
done: !prevState.todos[i].done,
}
}
return item;
})
}
})
}
handleDelete = (id) => {
this.setState({
todos: this.state.todos.filter(item => item.id !== id)
})
}
deleteCompleted = () => {
this.setState({
todos: this.state.todos.filter(item => !item.done)
})
}
getVisibleTodos = () => {
const filterType = this.state.filterType;
let filterState = null;
switch (filterType) {
case "Completed":
return filterState = this.state.todos.filter(item => item.done);
case "Active":
return filterState = this.state.todos.filter(item => !item.done);
case "Originals":
return filterState = this.state.todos.filter(item => !item.done);
case "New":
return filterState = this.state.todos.filter(item => !item.done);
default:
return filterState = this.state.todos;
}
}
setActiveFilter = (text) => {
this.setState({
filterType: text,
})
}
render() {
return (
<div className="container">
<Header countTodo={this.state.todos.length}/>
<Form handleDelete={this.handleDelete}
handleToggle={this.handleToggle}
handleClick={this.handleClick}
handleChange={this.handleChange}
todoValue={this.state.todoValue}
todos={this.getVisibleTodos()}/>
<Footer setActiveFilter={this.setActiveFilter}
deleteCompleted={this.deleteCompleted}
filter={this.state.filterType}/>
</div>
)
}
}
export default App;
Header.js
import React from 'react';
class Header extends React.Component {
render() {
return (
<header className="header">
<h3>All To-Do {this.props.countTodo}</h3>
</header>
)
}
}
export default Header;
Form.js
import React, {Component} from'react';
import Todo from './Todo';
class Form extends React {
render() {
return (
<form className="form">
<input type="text"
className="form__input"
placeholder="Items"
onChange={this.props.handleChange}
value={this.props.todoValue}
/>
<button
className="form__button"
type="submit"
onClick={this.props.handleClick}>╋</button>
<Todo
todos={this.props.todos}
handleToggle={this.props.handleToggle}
handleDelete={this.props.handleDelete}
/>
</form>
)
}
}
export default Form;
and the last modul is Todo.js
import React, {Component} from 'react';
class Todo extends React{
render() {
return (
<ul className="todos-list">
{
this.props.todos.map((item) => {
return (
<li className="todo-item"
key={item.id} onClick={() => this.props.handleToggle(item.id)}>
<span
className={item.done ? "todo-item__name disabled" : "todo-item__name"}>
{item.text}
</span>
<span
className="todo-item__delete-button"
onClick={() => this.props.handleDelete(item.id)}>
×
</span>
</li>
)
})
}
</ul>
)
}
}
export default Todo;
You class should extend from Component that you're importing from react library.
It should be either
class App extends Component{}
or if you didn't import Component then
class App extends React.Component{}
You haven't extended your App component correctly
class App extends React{ // error here
constructor(props) {
this.state = {
todoValue: "",
filterType: "All",
todos: [],
}
}
Extend it from React.Component
class App extends React.Component {
constructor(props) {
super(props); // use super here
this.state = {
todoValue: "",
filterType: "All",
todos: [],
}
}

Resources