两个功能性 React JS 组件之间的双向通信
Two way communication between two functional React JS components
我在 React 中内置了两个功能组件,一个是 Item 组件 - 它包含一些关于东西的数据,带有可选图形、一些文本数据和价格信息。在底部有一个按钮,允许您 select 这个特定的项目。它还在其道具中保留有关当前 selected Item 的 ID 的信息 - 这就是我计划解决此问题的方式。
我的第二个组件是 ItemList - 它基本上包含一个前面提到的项目列表 - 而且它对所有项目进行排序,并且必须保留有关当前哪个组件的信息 selected - selected 基本上看起来不同 - 一些东西比如边框和按钮的颜色通过 CSS.
切换
我的实现逻辑是这样的——当用户点击一个特定项目的“Select”按钮时,该项目应该改变它的外观(除非它已经 selected,然后做什么都没有),然后以某种方式将信息传播到 ItemList,以便它可以“禁用”先前 selected 的组件。只能有一个 selected Item,一旦用户决定 select 另一个,之前的 selected 应该改变它的状态并去回到未selected 标准图形样式。
我已经 运行 解决了 ItemList 组件中的状态加上通过 props 将函数传递给 Item ,但这并没有解决第二部分 - ItemList 需要获取有关更改的信息,因此它可以根据实际状态重新呈现所有组件。我应该深入研究 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 中,the data flows down,因此您最好将状态数据保存在呈现表示组件的有状态组件中。
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>
我在 React 中内置了两个功能组件,一个是 Item 组件 - 它包含一些关于东西的数据,带有可选图形、一些文本数据和价格信息。在底部有一个按钮,允许您 select 这个特定的项目。它还在其道具中保留有关当前 selected Item 的 ID 的信息 - 这就是我计划解决此问题的方式。
我的第二个组件是 ItemList - 它基本上包含一个前面提到的项目列表 - 而且它对所有项目进行排序,并且必须保留有关当前哪个组件的信息 selected - selected 基本上看起来不同 - 一些东西比如边框和按钮的颜色通过 CSS.
切换我的实现逻辑是这样的——当用户点击一个特定项目的“Select”按钮时,该项目应该改变它的外观(除非它已经 selected,然后做什么都没有),然后以某种方式将信息传播到 ItemList,以便它可以“禁用”先前 selected 的组件。只能有一个 selected Item,一旦用户决定 select 另一个,之前的 selected 应该改变它的状态并去回到未selected 标准图形样式。
我已经 运行 解决了 ItemList 组件中的状态加上通过 props 将函数传递给 Item ,但这并没有解决第二部分 - ItemList 需要获取有关更改的信息,因此它可以根据实际状态重新呈现所有组件。我应该深入研究 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 中,the data flows down,因此您最好将状态数据保存在呈现表示组件的有状态组件中。
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>