我可以从 ReactJS 的父元素中检索属性值吗?

Can I retrieve a attribute value from a parent element in ReactJS?

当我点击一个特定的按钮时,我想捕获与其关联的 {country} 属性。 我厌倦了以下

import React, { useState, useEffect } from 'react'
import axios from 'axios'


// ====================================================================[SEARCH-BAR]=======================================================
// search component
const SearchBar = (props) => {
    // console.log(props);
    const { searchString, searchOnChangeEventHandler } = props
    return (
        <>
            <form>
                <label>Search </label>
                <input type='text' placeholder='type to search...' value={searchString} onChange={searchOnChangeEventHandler} />
            </form>
        </>
    )
}

// ================================================================[COUNTRY_CARD]==========================================================
// countryCard component
const CountryCard = (props) => {
    console.log(props);
    return (
        <div>
            <p>countryName</p>
            <p>capital</p>
            <p>population</p>
            <p>languages</p>
            <ul>
                <li>item</li>
                <li>item</li>
            </ul>
            <p>image flag</p>
        </div>
    )
}


// ===================================================================[DISPLAY]===========================================================
// display component
const Display = (props) => {
    const [showCountryCard, setShowCountryCard] = useState(false)
    const [thisCountry, setThisCountry] = useState({})
    // console.log(props);
    const { countries, searchString } = props
    // console.log(countries);
    // eslint-disable-next-line eqeqeq

    // searchString empty
    if (searchString == false) {
        return (
            <>
                <div>
                    <span>Type in SearchBar for a country...</span>
                </div>
            </>
        )
    }

    // to count number of matches
    const filteredResultsCount = countries.filter(country => country.name.toLowerCase().includes(searchString.toLowerCase())).length
    // function to filterCountries
    const filteredResults = (searchString, countries) => countries.filter(country => {
        return country.name.toLowerCase().includes(searchString.toLowerCase())
    })

    // RENDER CONDITIONS
    // searchString return <= 10 matches && >1 match
    // event handler for show-btn
    const showCardEventHandler = (event) => {
        console.log(event.target.parentElement);
        setShowCountryCard(!showCountryCard)
    }
    if (filteredResultsCount <= 10 && filteredResultsCount > 1) {
        return (
            <>
                <ul>
                    {
                        filteredResults(searchString, countries).map(country =>
                            <li
                                key={country.numericCode}
                                country={country}
                            >
                                <span>{country.name}</span>
                                <button
                                    value={showCountryCard}
                                    onClick={showCardEventHandler}
                                >show</button>
                            </li>
                        )
                    }
                </ul>
                {
                    showCountryCard ? <p>show country card</p> : null
                }
            </>
        )
    }
    // searchString returns >10 matches
    if (filteredResultsCount > 10) {
        return (
            <span>{filteredResultsCount} matches!, please refine your search...</span>
        )
    }
    // searchString returns ===1 match
    if (filteredResultsCount === 1) {
        return (
            <>
                {
                    filteredResults(searchString, countries).map(country => <CountryCard key={country.numericCode} country={country} />)
                }
            </>

        )
    }
    // invalid searchString
    if (filteredResultsCount === 0) {
        return (
            <span><strong>{filteredResultsCount} matches!</strong> please refine your search...</span>
        )
    }
}

// ===================================================================[APP]==============================================================
// app component
const App = () => {
    // to store countries
    const [countries, setCountries] = useState([])

    // to fetch data from 
    const url = 'https://restcountries.eu/rest/v2/all'
    useEffect(() => {
        // console.log('effect');
        axios
            .get(url)
            .then(response => {
                // console.log('promise fulfilled');
                const countries = response.data
                // array of objects
                setCountries(countries)
            })
    }, [])
    // console.log('countries', countries.length);
    // console.log(countries);

    // to store search string
    const [searchString, setSearchString] = useState('')
    // event handler search input
    const searchOnChangeEventHandler = (event) => setSearchString(event.target.value)

    return (
        <>
            <h1>Countries Data</h1>
            <SearchBar searchString={searchString} searchOnChangeEventHandler={searchOnChangeEventHandler} />
            <br />
            <Display countries={countries} searchString={searchString} />
        </>
    )
}

export default App

请看一下 <Display/> 组件,特别是我正在努力处理这部分

    const showCardEventHandler = (event) => {
        console.log(event.target.parentElement);
        setShowCountryCard(!showCountryCard)
    }
    if (filteredResultsCount <= 10 && filteredResultsCount > 1) {
        return (
            <>
                <ul>
                    {
                        filteredResults(searchString, countries).map(country =>
                            <li
                                key={country.numericCode}
                                country={country}
                            >
                                <span>{country.name}</span>
                                <button
                                    value={showCountryCard}
                                    onClick={showCardEventHandler}
                                >show</button>
                            </li>
                        )
                    }
                </ul>
                {
                    showCountryCard ? <p>show country card</p> : null
                }
            </>
        )
    }

我希望能够呈现超过 10 个国家的列表,并允许用户单击特定国家,然后将用于呈现 <CountryCard/> 组件。 如果从搜索中只有 1 个匹配值,那么我将直接显示国家卡组件。第二个功能有效。
在以下重构之后,第一个功能起作用了,但我有点困惑为什么我要添加到 post。这是正在渲染的组件,现在我正在传递 country prop onClick,就像这样

    if (filteredResultsCount <= 10 && filteredResultsCount > 1) {
        return (
            <>
                <ul>
                    {filteredResults(searchString, countries).map((country) => (
                        <li key={country.numericCode} country={country}>
                            <span>{country.name}</span>
                            <button
                                value={showCountryCard}
                                onClick={() => toggleCardEventHandler(country)}>
                                {showCountryCard ? 'hide' : 'show'}
                            </button>
                        </li>
                    ))}
                </ul>
                {showCountryCard ? <CountryCard country={country} /> : null}
            </>
        );
    }

事件处理如下

    const toggleCardEventHandler = (country) => {
        // console.log(country);
        setShowCountryCard(!showCountryCard);
        setCountry(country)
    };

这工作正常。 我的问题是,当我更改 eventHandler onClick={toggleCardEventHandler(country)} 它会中断,但它不应该通过闭包访问吗?

另外,如果我把代码改成这样

onClick={() => {
    toggleCardEventHandler()
    setCountry(country)
}}

代码按我想要的方式运行,但哪种方式更好,可以将值传递给 toggleCardEventHandler() 并在那里设置国家/地区或像这样设置?

据我了解,您想将 country.name 传递给您的 showCardEventHandler。 更新 showCardEventHandler 以获取事件和国家名称:

const showCardEventHandler = (event, countryName) => {
  console.log(countryName);
  setShowCountryCard(!showCountryCard)
}

现在将国家名称传递给函数:

<li
  key={country.numericCode}
  country={country}
>
 <span>{country.name}</span>
 <button
   value={showCountryCard}
   onClick={e => showCardEventHandler(e, country.name)}
 >show</button>
</li>

由于您没有使用 showCardEventHandler 中的事件,您可以将其从签名中删除 const showCardEventHandler = (countryName) => {} 并用 onClick={() => showCardEventHandler(country.name)}

调用它