Реагировать на хук useState - я хочу отображать определенный компонент, когда нажимаю только кнопку отправки, а не при onChange

Я новичок в реакции.

Теперь пытаюсь создать форму с помощью хуков реакции, и я хочу отображать компонент Cloud только при нажатии кнопки отправки. Но он отображал каждый вызов onChange.

Я знаю, что повторный рендеринг onChange также вызывает перехватчик useState.

Но понятия не имею, как рендерить только при нажатии кнопки отправки.

Моя конечная цель - написать имя и нажать Enter, если значение не содержится в api, setShake make shake 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;

Cloud.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.log(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;

person Adorevoy    schedule 25.12.2020    source источник


Ответы (2)


Хороший подход в этом случае - использовать 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, и таким образом не будет повторной визуализации в вашем коде.

person Imran Rafiq Rather    schedule 25.12.2020
comment
Вы очень добры. Мне нравится помогать людям. Всевышний Аллах дает мне мир и умиротворение. Ага, праздники идут хорошо. Надеюсь, ваш тоже хороший :) - person Imran Rafiq Rather; 25.12.2020

Сделай это так

Если вы хотите отобразить облачный компонент после отправки формы, поставьте один флаг и переключите его, здесь я беру состояние 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;
person Nisharg Shah    schedule 25.12.2020
comment
Спасибо!! И счастливого Рождества;) - person Adorevoy; 25.12.2020