I am trying to convert class component of todo app into functional component. Everything goes well, but when I submit the form, the blank screen appears. I think there is some issue in handleSubmit function. Please help.
import React, {useState} from "react";
export const TodoFunc = (props: Props) => {
const [items, setItems] = useState([])
const [text, setText] = useState('')
const handleChange = (e) => {
setText(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault()
if (text.length === 0) {
return;
}
const newItems = {text: {text}, id: Date.now()}
setItems(() => (items.concat(newItems)))
setText('')
}
return (
<div>
<h3>TODO</h3>
<TodoList items = {items} />
<form onSubmit={handleSubmit}>
<label htmlFor="new-todo">
What do you want to do?
</label>
<input type="text"
id='new-todo'
onChange={handleChange}
value={text}
/>
<button>
Add #{items.length + 1}
</button>
</form>
</div>
);
};
const TodoList = (props) => {
return (
<ul>
{props.items.map(item => <li key={item.id}>{item.text}</li>)}
</ul>
)
}
Your problem lies in the below line:
const newItems = {text: {text}, id: Date.now()}
Here you are assigning an object to the text key and not just the value of the variable text.
And this is why when you loop over them in your TodoList component you are not able to display any of them.
Related
Please help with the task. I have 2 components: Header, which has a Modal component (for a modal window) and a Main_Part component. I don't know how to make so that on the Create button values from input were created in the Main_part component.
How can this be done? Thanks
Main_part.js
import React from "react";
import "./Main_Part.css";
export let Main_Part = ({newList}) => {
return (<div className="main">
</div>)
}
Header.js
import React, {useState} from "react";
import "./Header.css";
import {Modal} from "../Modal/Modal";
import {Main_Part} from "../Main_Part/Main_Part";
export let Header = () => {
let [modalActive, setModalActive] = useState(false);
let [newList, setNewList] = useState([]);
let [input, setInput] = useState('');
let addList = (myInput) => {
let newDiscussion = {
id: Math.random(),
task: myInput
}
setNewList([...newList, newDiscussion])
}
let handleInput = (e) => {
setInput(e.target.value)
}
let submitTask = (e) => {
e.preventDefault();
addList(input);
setInput('')
}
return (<header className="header">
<div>
<button onClick={() => setModalActive(true)}>Створити новий список</button>
</div>
<Modal active={modalActive} setActive={setModalActive}>
<form onSubmit={submitTask}>
<input
type="text"
placeholder="Створити"
onChange={handleInput}
/>
<button type="submit" onSubmit={submitTask}>Create</button>
</form>
<button onClick={() => setModalActive(false)}>Закрити</button>
</Modal>
<Main_Part newList={newList}/>
</header>)
}
Here's the simple sample of what you're wanting to do. You just need to pass the input values to Main_Part and check its for not null definition in Main_Part:
newList && newList.map((v, i) => v.task)
Here's the example:
import { useState } from "react";
import "./styles.css";
const Main_Part = ({ newList }) => {
return <div className="main">{newList && newList.map((v, i) => v.task)}</div>;
};
const Header = () => {
let [modalActive, setModalActive] = useState(false);
let [newList, setNewList] = useState([]);
let [input, setInput] = useState("");
let addList = (myInput) => {
let newDiscussion = {
id: Math.random(),
task: myInput
};
setNewList([...newList, newDiscussion]);
};
let handleInput = (e) => {
setInput(e.target.value);
};
let submitTask = (e) => {
e.preventDefault();
addList(input);
setInput("");
};
return (
<header className="header">
<form onSubmit={submitTask}>
<input type="text" placeholder="Створити" onChange={handleInput} />
<button type="submit" onSubmit={submitTask}>
Create
</button>
</form>
<button onClick={() => setModalActive(false)}>Закрити</button>
<Main_Part newList={newList} />
</header>
);
};
export default function App() {
return (
<>
<Header />
<Main_Part />
</>
);
}
I'm new to React, so please explain why this is happens(I guess because I'm re-creating the array of objects, but I'm not sure and don't know how to fix this) and how to fix this this.
I think it's better to show the code, rather than talk about it, so:
App.js
import { useState } from "react";
import Input from "./Input";
let lastId = 2;
function App() {
const [inputsValues, setInputsValues] = useState([
{ id: 1, value: "" },
{ id: 2, value: "" },
]);
const handleChange = (e, id) => {
setInputsValues((prevState) => {
const newState = [...prevState];
const index = newState.findIndex((input) => input.id === id);
newState[index].value = e.target.value;
return newState;
});
};
const addNewInput = () => {
setInputsValues((prevState) => {
const newState = [...prevState];
newState.push({ id: ++lastId, value: "" });
return newState;
});
};
return (
<div className="App">
<div>
<button onClick={addNewInput}>Add new input...</button>
</div>
{inputsValues.map((input) => (
<div className="input-wrap">
<Input
key={input.id}
id={input.id}
value={input.value}
handleChange={handleChange}
/>
</div>
))}
</div>
);
}
export default App;
Input.js
import { useRef } from "react";
const Input = ({ id, value, handleChange }) => {
const renderAmount = useRef(0);
return (
<>
<div> Rendered: {renderAmount.current++}</div>
<input
id={id}
type="text"
value={value}
onChange={(e) => handleChange(e, id)}
/>
</>
);
};
export default Input;
Thanks
Seems like you just have to wrap your Input component in memo so that it only rerenders if its props change. So i imported the memo function in the top and called it on the right side of the assignment, so that it 'wraps' your component and makes it memoized.
import { useRef, memo } from "react";
const Input = memo(({ id, value, handleChange }) => {
const renderAmount = useRef(0);
return (
<>
<div> Rendered: {renderAmount.current++}</div>
<input
id={id}
type="text"
value={value}
onChange={(e) => handleChange(e, id)}
/>
</>
);
});
export default Input;
I have a component Search component with suggestions. I create the suggestions by javascript. I can print all the suggestions, but how I can select the suggest element to put into the placeholder? Thanks for your response.
SEARCH COMPONENT
import React, { useEffect, useState } from "react";
import api from "../../api/index";
import "./index.css";
export default function Search(query) {
const [searchSchool, setSearchShool] = useState("");
const [showSuggestions, setShowSuggestions] = useState(false);
const [allSchools, setAllSchools] = useState([]);
const inputRef = React.useRef(null);
useEffect(() => {
(async () => {
const data = await api.getSchools();
setAllSchools(data);
})();
}, []);
const resultsAllSchools = !searchSchool
? allSchools
: allSchools.filter(school => school.toLowerCase().includes(searchSchool));
const handleOnclick = e => {
e.preventDefault();
const lowerCase = e.target.value.toLowerCase();
setSearchShool(lowerCase);
setShowSuggestions(true);
if (e.target.value === "" || null) {
setShowSuggestions(false);
}
};
return (
<>
<form>
<input
className="select"
type="text"
placeholder="Cerca el teu centre educatiu"
value={searchSchool}
ref={inputRef}
onChange={handleOnclick}
></input>
<button>
</button>
<ul>
{showSuggestions &&
resultsAllSchools.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</form>
</>
);
}
I'm trying to build edit form fields. Here, you have to press a button before you can edit the form field. However, I'm having problems toggling the disabled prop and setting the focus of the element. This is some sample code. The input will only focus after I've clicked the button twice.
export default function App() {
const [isDisabled, setIsDisabled] = useState(true);
const inputEl = useRef(null);
const onBlur = () => {
setIsDisabled(true);
};
const handleEditClick = () => {
setIsDisabled(false);
inputEl.current.focus();
};
return (
<div className="App">
<h1>Focus problem</h1>
<h2>Focus only happens on the scond click!</h2>
<input ref={inputEl} onBlur={onBlur} disabled={isDisabled} />
<button onClick={() => handleEditClick()}>Can edit</button>
</div>
);
}
Here is a code-sandbox
Setting focus on a DOM element is a side-effect, it should be done within useEffect:
import React, { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function App() {
const [isDisabled, setIsDisabled] = useState(true);
const inputEl = useRef(null);
useEffect(() => {
inputEl.current.focus();
}, [isDisabled]);
const onBlur = () => {
setIsDisabled(true);
};
const handleEditClick = () => {
setIsDisabled(false);
};
return (
<div className="App">
<h1>Focus problem</h1>
<h2>Focus only happens on the scond click!</h2>
<input ref={inputEl} onBlur={onBlur} disabled={isDisabled} />
<button onClick={() => handleEditClick()}>Can edit</button>
</div>
);
}
Hello guys,
I'm relatively new to react hooks, and back in my time(one year ago), when I was passing props through
component, I would then use them with "props.something."
Now I have done a "todo list" and I can use my props in another way, by referencing the props in an objet in parameter :
const Form = ({ addTodo }) => {
addTodo(x)
}
What is that ? Why we don't use this.props anymore, why the object in parameter ? Is the old way passing props dead ? Is this because of react Hooks ?
To illustrate more my exemple here the two component talking to eachother.
The first one :
import React, {useState} from 'react';
import Form from './Form';
const Affichage = () => {
const [todos, setTodos] = useState([
'1',
'2',
'3',
'4'
])
const addTodo = text => {
const newTodos = [...todos, text];
setTodos(newTodos)
}
return (
<div>
<Form addTodo={addTodo} />
<ul>
{todos.map((item, index) =>{
return(
<li key={index}>
{item}
</li>
)
})}
</ul>
</div>
)
}
export default Affichage;`
The second one :
import React, {useState} from 'react';
const Form = ({ addTodo }) => {
const [value, setValue] = useState('');
const handleSubmit = e => {
e.preventDefault();
// console.log(value);
addTodo(value);
}
return(
<form onSubmit={handleSubmit}>
<input type="text" onChange={e => setValue(e.target.value)}/>
<button>Envoyer</button>
</form>
)
}
export default Form;
If someone passing by could enlight me it would awesome ☺
Nothing changed. It's just a shortcut for destructuring
const Component = props =>{
const { foo } = props
}
Is the equivalent of
const Component = ({ foo }) =>{
}