0

我是新来的反应。

现在试图用反应钩子制作表单,我只想在按下提交按钮时渲染云组件。但它渲染了每个 onChange 调用。

我知道 onChange 重新渲染的原因也是 useState 钩子。

但是只有在按下提交按钮时才知道如何渲染。

我的最终目标是在写入名称并按 Enter 时,如果值不包含在 api 中,则 setShake 使摇动为真,如果为真,则将摇动云类放入 Cloud.js。

反应太难了:(

谢谢你的帮助:)

应用程序.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;
4

2 回答 2

1

那样做

如果你想在表单提交后渲染云组件然后放一个标志并切换它,我在这里接受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;
于 2020-12-25T11:53:23.463 回答
1

在这种情况下,一个好的方法是使用useRef()Hook 来存储我们的搜索字段值,而不是使用useState(). 因为useRef() Hook does not force a re-renderwhileuseState()确实如此。这种方法被称为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();
};

假设用户输入了一个输入。getSearch()如果没有,那么您可以在表单提交处理程序中使用 setQuery() 之前设置验证。

if(search.current.value){
   setQuery();
}

注意: 如果您controlled inputs的项目中有任何其他内容,您可以un-controlled使用然后更改为输入refs,这样您的代码中就不会发生重新渲染。

于 2020-12-25T12:20:00.070 回答