[英]Two way communication between two functional React JS components
我在 React 中構建了兩個功能組件,一個是Item組件——它包含一些關於東西的數據,帶有可選的圖形、一些文本數據和價格信息。 在底部有一個按鈕,可以讓你 select 這個特定項目。 它還在其道具中保存有關當前所選項目ID 的信息——這就是我計划解決此問題的方式。
我的第二個組件是ItemList - 它基本上包含一個前面提到的項目列表 - 加上它對所有項目進行排序,並且必須保留有關當前選擇哪個組件的信息 - 所選組件基本上看起來不同 - 一些東西,比如邊框框和按鈕的顏色通過 CSS 切換。
我的實現邏輯是這樣的——當用戶點擊特定項目的“選擇”按鈕時,項目應該改變它的外觀(除非它已經被選中,然后什么都不做),然后以某種方式將信息傳播到ItemList上,所以它可以“禁用”先前選擇的組件。 只能選擇一個Item ,一旦用戶決定 select 另一個,之前選擇的應該將其 state 和 go 更改回未選擇的標准圖形樣式。
我在ItemList組件中遇到了 state 的解決方案,並通過道具將 function 通過道具傳遞給Item ,但這並不能解決第二部分 - ItemList需要獲取有關更改的信息,因此它可以根據實際 state。 我應該深入研究 React API 的哪一部分來解決這個問題?
這是我的組件的代碼:
物品
interface Props {
receivedObject: itemToDisplay;
selectedItemId: string;
onClick?: () => void;
}
export default function Item(props: Props) {
const {name, description, price} = props.receivedObject;
const imageUrl = props.receivedObject?.media?.mainImage?.small?.url;
const priceComponent = <Price price={price}/>;
const [isItemSelected, setSelection] = useState(props.selectedItemId == props.receivedObject.id);
const onClick = props.onClick || (() => {
setSelection(!isItemSelected)
});
return (
<>
<div className="theDataHolderContainer">
// displayed stuff goes here
<div className="pickButtonContainer">
// that's the button which should somehow send info "upwards" about the new selected item
<Button outline={isItemSelected} color="danger" onClick={onClick}>{isItemSelected ? "SELECTED" : "SELECT"}</Button>
</div>
</div>
</>)
};
物品清單
interface Props {
packageItems: Array<itemToDisplay>
}
export default function ItemList(props: Props) {
const itemsToDisplay = props.packageItems;
itemsToDisplay.sort((a, b) =>
a.price.finalPrice - b.price.finalPrice
);
let selectedItemId = itemsToDisplay[0].id;
const [currentlySelectedItem, changeCurrentlySelectedItem] = useState(selectedItemId);
const setSelectedItemFunc = () => {
/* this function should be passed down as a prop, however it can only
* have one `this` reference, meaning that `this` will refer to singular `Item`
* how do I make it change state in the `ItemList` component?
*/
console.log('function defined in list');
};
return(
<div className="packageNameList">
<Item
key={itemsToDisplay[0].id}
receivedObject={itemsToDisplay[0]}
onClick={setSelectedItemFunc}
/>
{itemsToDisplay.slice(1).map((item) => (
<Item
key={item.id}
receivedObject={item}
onClick={setSelectedItemFunc}
/>
))}
</div>
);
}
在 React 中, 數據是向下流動的,因此您最好將 state 數據保存在呈現表示組件的有狀態組件中。
function ListItem({ description, price, selected, select }) { return ( <li className={"ListItem" + (selected? " selected": "")}> <span>{description}</span> <span>${price}</span> <button onClick={select}>{selected? "Selected": "Select"}</button> </li> ); } function List({ children }) { return <ul className="List">{children}</ul>; } function Content({ items }) { const [selectedId, setSelectedId] = React.useState(""); const createClickHandler = React.useCallback( id => () => setSelectedId(id), [] ); return ( <List> {items.sort(({ price: a }, { price: b }) => a - b).map(item => ( <ListItem key={item.id} {...item} selected={item.id === selectedId} select={createClickHandler(item.id)} /> ))} </List> ); } function App() { const items = [ { id: 1, description: "#1 Description", price: 17 }, { id: 2, description: "#2 Description", price: 13 }, { id: 3, description: "#3 Description", price: 19 } ]; return ( <div className="App"> <Content items={items} /> </div> ); } ReactDOM.render( <App />, document.getElementById("root") );
.App { font-family: sans-serif; }.List >.ListItem { margin: 5px; }.ListItem { padding: 10px; }.ListItem > * { margin: 0 5px; }.ListItem:hover { background-color: lightgray; }.ListItem.selected { background-color: darkgray; }
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.