簡體   English   中英

使用 Hooks 和標簽更新 React state

[英]Updating React state with Hooks and tags

我對如何在 2 種情況下使用鈎子更新 React state 有語法疑問。

1)我有一個名為公司的 state 和一個填寫它的表格。 在聯系部分,有兩個輸入是指公司員工(姓名和電話號碼)。 但是,如果公司有多個要聯系的員工,則有一個“添加更多聯系人”按鈕,該按鈕必須復制相同的輸入(當然,針對第二個聯系人)。 我怎樣才能做到這一點? 我的意思是,要在 state 內的數組“聯系人”中生成另一個索引,增加具有該數組的 object 內的 totalOfContacts 並創建輸入標簽,以便用戶可以鍵入第二個聯系人的數據?

2)當我輸入任何輸入時,代碼會觸發 handleChange function。 “名稱”和“城市”已經更新了 state,因為它們是簡單的狀態。 但是我如何更新聯系人姓名和他的電話號碼,因為它們是 state 內數組索引的一部分?

下面的代碼已經在運行,我的 2 個問題正是注釋的兩行(第 20 行和第 29 行)。

“保存”按鈕只是簡單地控制台記錄結果,以便我們可以監控它們。

現在謝謝。

在此處輸入圖像描述

import React, { useState, useEffect } from "react";

export default () => {
    const [company, setCompany] = useState({
        name: "", city: "",
        contact: {
            totalOfContact: 1,
            contacts: [
                {id: 0, contactName: "", telephoneNumber: ""}
            ]
        }
    })

    useEffect(() => {
        console.log("teste");
    })

    const handleChange = item => e => {
        if (item === "contactName" || "telephone") {
            // How can I set company.contact.contacts[<current_index>].contactName/telephoneNumber with the data typed?
        } else {
            setCompany({ ...company, [item]: e.target.value })
        }
    }

    const handleClick = (e) => {
        e.preventDefault();
        if (e.target.value === "add") {
            // How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact?
        } else {
            console.log(`The data of the company is: ${company}`);
        }
    }

    return (
        <div>
            <form>
                <h3>General Section</h3>
                Name: <input type="text" onChange = {handleChange("name")} value = {company.name} />
                <br />
                City: <input type="text" onChange = {handleChange("city")} value = {company.city} />
                <br />
                <hr />
                <h3>Contacts Section:</h3>
                Name: <input type="text" onChange = {handleChange("contactName")} value = {company.contact.contacts[0].name} />
                Telephone Numer: <input type="text" onChange = {handleChange("telephone")} value = {company.contact.contacts[0].telephoneNumber} />
                <br />
                <br />
                <button value = "add" onClick = {(e) => handleClick(e)} >Add More Contact</button>
                <br />
                <br />
                <hr />
                <button value = "save" onClick = {(e) => handleClick(e)} >Save</button>
            </form>
        </div>
    )
}

為了回答你的問題,讓我們把這個問題簡化為一個更簡單的問題,即如何處理聯系人數組

你只需要知道以下幾點:

  1. Map function
  2. 如何更新數組

我將使用 TypeScript 以便您更好地理解。

const [state, setState] = React.useState<{
    contacts: {name: string}[]
}>({contacts: []})

return (
    <div>
        {state.contacts.map((contact, index) => {
            return (
                <div>
                    Name: 
                    <input value={contact.name} onChange={event => {
                      setState({
                          ...state,
                          contacts: state.contacts.map((contact$, index$) => 
                              index === index$
                                 ? {...contact$, name: event.target.value}
                                 : {...contact$}

                          )
                      })
                    }}/>
                </div>
            )
        }}
    </div>
)

此外,這種問題在 React 中相當普遍,因此理解和記住這種模式會對你有很大幫助。

要更新 state 值,您可以使用functional setState

const handleChange = item => e => {
    //Take the value in a variable for future use
    const value = e.target.value;
    if (item === "contactName" || "telephone") {
        setCompany(prevState => ({
          ...prevState,
          contact: {...prevState.contact, contacts: prevState.contact.contacts.map(c => ({...c, [item]: value}))}
        }))
    } else {
        setCompany({ ...company, [item]: e.target.value })
    }
}

要在單擊按鈕時添加新的輸入集,您可以這樣做,

const handleClick = (e) => {
    e.preventDefault();
    //This is new set of input to be added
    const newSetOfInput = {id: company.contact.contacts.length, contactName: "", telephoneNumber: ""}
    if (e.target.value === "add") {
        // How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact?
        setCompany(prevState => ({
          ...prevState,
          contact: {...prevState.contact, contacts: prevState.contact.contacts.concat(newSetOfInput), totalOfContact: prevState.contact.contacts.length + 1}
        }))
    } else {
        console.log(`The data of the company is: ${company}`);
    }
}

最后,您需要遍歷您的contacts數組,例如,

{company.contact.contacts && company.contact.contacts.length > 0 && company.contact.contacts.map(contact => (
    <div key={contact.id}>
    Name: <input type="text" onChange = {handleChange("contactName")} value = {contact.contactName} />
    <br/>
    Telephone Numer: <input type="text" onChange = {handleChange("telephoneNumber")} value = {contact.telephoneNumber} />
    </div>
))}

演示

注意:你應該使用像div這樣的塊元素,而不是使用<br/>

你可以做這樣的事情。

 import React, { useState, useEffect } from "react"; import ReactDOM from "react-dom"; const App = () => { const [company, setCompany] = useState({ name: "", city: "", contact: { totalOfContact: 1, contacts: [{id: 0, contactName: "", telephoneNumber: ""}] } }); console.log(company); useEffect(() => { console.log("teste"); }, []); const handleChange = (item, e,index) => { if (item === "contactName" || item === "telephoneNumber") { const contactsNew = [...company.contact.contacts]; contactsNew[index] = {...contactsNew[index], [item]: e.target.value }; setCompany({...company, contact: {...company.contact, contacts: contactsNew } }); // How can I set company.contact.contacts[<current_index>].contactName/telephoneNumber with the data typed? } else { setCompany({...company, [item]: e.target.value }); } }; const handleClick = e => { e.preventDefault(); if (e.target.value === "add") { const contactNew = {...company.contact}; contactNew.totalOfContact = contactNew.totalOfContact + 1; contactNew.contacts.push({id:contactNew.totalOfContact -1, contactName: "", telephoneNumber: ""}); setCompany({...company, contact: {...contactNew}}); // How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact? } else { alert("Push company to somewhere to persist"); console.log(`The data of the company is: ${company}`); } }; return ( <div> <form> <h3>General Section</h3> Name:{" "} <input type="text" onChange={(e) => handleChange("name", e)} value={company.name} /> <br /> City:{" "} <input type="text" onChange={(e) => handleChange("city", e)} value={company.city} /> <br /> <hr /> <h3>Contacts Section:</h3> {company.contact.contacts.map((eachContact, index) => { return <React.Fragment> Name:{" "} <input type="text" onChange={(e) => handleChange("contactName",e, index)} value={eachContact.name} /> Telephone Numer:{" "} <input type="text" onChange={(e) => handleChange("telephoneNumber",e, index)} value={eachContact.telephoneNumber} /> <br /> </React.Fragment> })} <br /> <button value="add" onClick={e => handleClick(e)}> Add More Contact </button> <br /> <br /> <hr /> <button value="save" onClick={e => handleClick(e)}> Save </button> </form> </div> ); }; const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);

您的 state 結構看起來是 useReducer 掛鈎的理想候選者。 我建議你試試這個,而不是 useState。 我想你的代碼應該看起來很可讀。 https://reactjs.org/docs/hooks-reference.html#usereducer

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM