Я новичок, чтобы реагировать.
Теперь пытаюсь создать форму с реагирующими хуками, и я хочу отображать облачный компонент только при нажатии кнопки отправки. Но он отображал каждый вызов onChange.
Я знаю, что повторная визуализация onChange также вызывает крючок useState.
Но понятия не имею, как отображать только при нажатии кнопки отправки.
Моя конечная цель - написать имя и нажать Enter, если значение не содержится в API, setShake сделать встряхивание True, а если True, поместить класс Shake-Cloud в Cloud.js.
РЕАКТИРОВАТЬ СЛИШКОМ СЛОЖНО :(
Спасибо за помощь :)
App.js
import React, { useState, useEffect } from "react";
import "./App.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSearch } from "@fortawesome/free-solid-svg-icons";
import "./search.css";
import PageTitle from "./component/PageTitle";
import Cloud from "./component/Cloud";
import Loading from "./component/Loading";
//https://api.color.pizza/v1/
//data.colors[0].name
const App = () => {
const [isLoading, setIsLoading] = useState(false);
const [colorNames, setColorNames] = useState("");
const [search, setSearch] = useState("");
const [query, setQuery] = useState("");
const [cloudHex, setCloudHex] = useState("ivory");
const [shake, setShake] = useState(false);
useEffect(() => {
getColorLists();
}, []);
const getColorLists = async () => {
const res = await fetch(`https://api.color.pizza/v1/`);
const data = await res.json();
await setColorNames(data);
setIsLoading(true);
};
const isColor = () => {
let makeUpper =
query.search(/\s/) == -1
? query.charAt(0).toUpperCase() + query.slice(1)
: query
.split(" ")
.map((i) => i.charAt(0).toUpperCase() + i.slice(1))
.join(" ");
for (let i = 0; i < colorNames.colors.length; i++) {
if (colorNames.colors[i].name == makeUpper) {
setCloudHex(colorNames.colors[i].hex);
return;
} else if (i == colorNames.colors.length - 1) {
return makeShake();
}
}
};
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
e.preventDefault();
setQuery(search);
isColor();
};
const makeShake = async () => {
await setShake(true)
await setShake(false)
}
return (
<>
{!isLoading ? (
<Loading />
) : (
<div className = "App">
<div className = "app-wrap">
<PageTitle />
<div className = "search-wrap">
<form onSubmit = {getSearch} className = "search-form">
<input
className = "search-bar"
type = "text"
value = {search}
onChange = {updateSearch}
/>
<button type = "submit" className = "search-button">
<FontAwesomeIcon
icon = {faSearch}
className = "search"
/>
</button>
</form>
</div>
<Cloud cloudhex = {cloudHex} shake = {shake} />
</div>
</div>
)}
</>
);
};
export default App;
Облако.js
import React, {useEffect} from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCloud } from "@fortawesome/free-solid-svg-icons";
import './cloud.css';
const Cloud = ({cloudhex, shake}) => {
useEffect(() => {
}, [])
console.info(shake)
return (
<div className = {`cloud-wrap ${ shake ? "shake-cloud":''}`}>
<span className = "cloudhexname">{cloudhex}</span>
<FontAwesomeIcon icon = {faCloud} className = "cloud" style = {{color:`${cloudhex}`}} />
</div>
);
};
export default Cloud;
Делай так
Если вы хотите отобразить облачный компонент после отправки формы, поставьте один флаг и переключите его, здесь я беру состояние clicked
import React, { useState, useEffect } from "react";
import "./App.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSearch } from "@fortawesome/free-solid-svg-icons";
import "./search.css";
import PageTitle from "./component/PageTitle";
import Cloud from "./component/Cloud";
import Loading from "./component/Loading";
//https://api.color.pizza/v1/
//data.colors[0].name
const App = () => {
const [isLoading, setIsLoading] = useState(false);
const [colorNames, setColorNames] = useState("");
const [search, setSearch] = useState("");
const [query, setQuery] = useState("");
const [cloudHex, setCloudHex] = useState("ivory");
const [shake, setShake] = useState(false);
const [clicked, setClicked] = useState(false);
useEffect(() => {
getColorLists();
}, []);
const getColorLists = async () => {
const res = await fetch(`https://api.color.pizza/v1/`);
const data = await res.json();
await setColorNames(data);
setIsLoading(true);
};
const isColor = () => {
let makeUpper =
query.search(/\s/) == -1
? query.charAt(0).toUpperCase() + query.slice(1)
: query
.split(" ")
.map((i) => i.charAt(0).toUpperCase() + i.slice(1))
.join(" ");
for (let i = 0; i < colorNames.colors.length; i++) {
if (colorNames.colors[i].name == makeUpper) {
setCloudHex(colorNames.colors[i].hex);
return;
} else if (i == colorNames.colors.length - 1) {
return makeShake();
}
}
};
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
e.preventDefault();
setClicked(true);
setQuery(search);
isColor();
};
const makeShake = async () => {
await setShake(true)
await setShake(false)
}
return (
<>
{!isLoading ? (
<Loading />
) : (
<div className = "App">
<div className = "app-wrap">
<PageTitle />
<div className = "search-wrap">
<form onSubmit = {getSearch} className = "search-form">
<input
className = "search-bar"
type = "text"
value = {search}
onChange = {updateSearch}
/>
<button type = "submit" className = "search-button">
<FontAwesomeIcon
icon = {faSearch}
className = "search"
/>
</button>
</form>
</div>
{clicked && <Cloud cloudhex = {cloudHex} shake = {shake} />}
</div>
</div>
)}
</>
);
};
export default App;
Хороший подход в этом случае — использовать useRef()
Hook для хранения значения нашего поля поиска вместо использования useState()
. Потому что useRef()
Hook does not force a re-render
в то время как useState()
делает. Этот подход известен как un-controlled
способ использования поля ввода.
В основном вам нужно внести несколько изменений в свой код, а именно:
const search = useRef("");
Затем удалите onChange = {updateSearch}
и value = {search}
из input
и используйте свойство ref = {search}
. Так что ваш ввод выглядит следующим образом:
<input
className = "search-bar"
type = "text"
ref = {search}
/>
Затем в обработчике отправки вы можете получить значение поля ввода, используя search.current.value
. Таким образом, ваш getSearch()
будет выглядеть
const getSearch = (e) => {
e.preventDefault();
setClicked(true);
setQuery(search.current.value);
isColor();
};
Предположим, что пользователь ввел ввод. Если нет, то вы можете установить проверку перед использованием setQuery() в обработчике отправки формы getSearch()
.
if (search.current.value){
setQuery();
}
Примечание. Если в вашем проекте есть какие-либо другие controlled inputs
, вы можете изменить их на un-controlled
с помощью refs
, и таким образом в вашем коде не будет повторного рендеринга.
Вы наиболее наиболее Добро пожаловать. Мне нравится помогать людям. Господь Всемогущий АЛЛАХ дает мне мир и покой. Да, праздники идут хорошо. Надеюсь, у вас тоже все хорошо :)
Спасибо!! И с Рождеством ;)