[英]How to re-render a particular component in React with setInterval or there is another way?
[英]React - How to re-render a component using another component?
我有一個NavBar
組件,其中包含動態生成的鏈接列表(這些鏈接是在查詢我的后端的某些categories
后生成的)。 這些鏈接存儲在 NavBar 的子組件中,稱為DrawerMenu
。
NavBar
是主App.js
組件的子組件。
在我的Category
組件中,我有一個刪除類別的“刪除”function。 一旦我刪除了一個類別,我想在NavBar
中刪除指向它的鏈接。 我將如何 go 這樣做?
對於進一步的上下文,我的組件如下所示:
class DrawerMenu extends Component {
state = {
menuItems: [] // Takes a series of objects of the shape { name: "", link: "" }
}
getData = (query) => {
// Query backend for category data and set it to this.state.menuItems
}
componentDidMount() {
this.getData(menuItemsQuery)
}
render() {
const { classes, handleDrawerClose, open } = this.props
const { menuItems } = this.state
const drawer = (classes, handleDrawerClose) => (
<div>
...
{
menuItems.map((menuItem, index) => (
<Link color="inherit" key={index} to={menuItem.link} className={classes.drawerLink} component={RouterLink}>
<ListItem button className={classes.drawerListItem} onClick={handleDrawerClose}>
<ListItemText primary={menuItem.name} />
</ListItem>
</Link>
))
}
...
</div>
)
...
return (
<div>
<Drawer
variant="temporary"
anchor='left'
open={open}
onClose={handleDrawerClose}
classes={{
paper: `${open ? classes.drawerOpen : null} ${!open ? classes.drawerClose : null}`,
}}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer(classes, handleDrawerClose)}
</Drawer>
</div>
)
}
}
function PrimarySearchAppBar(props) {
return (
<div className={classes.grow}>
...
<DrawerMenu
classes={classes}
handleDrawerClose={handleDrawerClose}
open={open}
/>
...
</div>
)
}
class Category extends Component {
...
deleteCategory = async () => {
// Code to request backend to delete category
this.props.history.push(`/`)
}
...
}
有兩種常見的方法:您可以使用 state 管理工具,如Redux
或將您的 state 作為道具傳遞到組件樹中。
Redux 常用於多個組件依賴於同一個 state 或依賴於 state 的組件向下傳遞好幾層時,傳遞它會很麻煩。
我假設您的組件樹不是很大,所以我將創建一個簡單的示例,將道具向下傳遞。
class DrawerMenu extends Component {
// We're gonna manage the state here, so the deletion
// will actually be handled by this component
state = {
menuItems: [] // Takes a series of objects of the shape { name: "", link: "" }
}
handleDelete = (id) => {
let updatedMenuItem = [...this.state.menuItems]; //Create a copy
updatedMenuItem = updatedMenuItem(item => item.id !== id) // Remove the
deleted item
this.setState({
menuItems: updatedMenuItem
})
}
...
// Then wherever you render the category component
<Category handleDelete = {handleDelete}/> //Pass a reference to the delete method
}
類別組件
class Category extends Component {
...
deleteCategory = async () => {
// Code to request backend to delete category
this.props.handleDelete(categoryId) //Pass the id of the category
this.props.history.push(`/`)
}
...
}
我建議閱讀有關 state 管理的內容,它是 React 中的核心概念,您將在任何地方使用它。 例如 Redux 和上下文 API。
不知道為什么 Dennis Vash 刪除了他們的答案,他們是正確的,但在解決方案中可能沒有足夠的描述性。
刪除類別的方法不是從類別組件內部調用后端本身,因為導航欄不知道您進行了調用,而是調用類別組件和共享的祖先中的回調導航欄刪除一個類別,然后從服務器重新請求類別列表。 在下面的示例中,這個共享的祖先是MyCategoriesProvider
因為類別組件可能在樹中的位置(或多個位置)與 NavBar 大不相同,所以最好使用上下文。
老實說,這是 redux 的好地方,但我不會向你推銷 redux,而只是演示一個 Context 解決方案。
// We're going to create a context that will manage your categories
// The only job of this context is to hold the current categories,
// and supply the updating functions. For brevity, I'll just give
// it a handleDelete function.
// Ideally, you'd also store the status of the request in this context
// as well so you could show loaders in the app, etc
import { createContext } from 'react';
// export this, we'll be using it later
export const CategoriesContext = createContext();
// export this, we'll render it high up in the app
// it will only accept children
export const MyCategoriesProvider = ({children}) => {
// here we can add a status flag in case we wanted to show a spinner
// somewhere down in your app
const [isRequestingCategories,setIsRequestingCategories] = useState(false);
// this is your list of categories that you got from the server
// we'll start with an empty array
const [categories,setCategories] = useState([]);
const fetch = async () => {
setIsRequestingCategories(true);
setCategories(await apiCallToFetchCategories());
setIsRequestingCategories(false);
}
const handleDelete = async category => {
await apiCallToDeleteCategory(category);
// we deleted a category, so we should re-request the list from the server
fetch();
}
useEffect(() => {
// when this component mounts, fetch the categories immediately
fetch();
// feel free to ignore any warnings if you're using a linter about rules of hooks here - this is 100% a "componentDidMount" hook and doesn't have any dependencies
},[]);
return <CategoriesContext.Provider value={{categories,isRequestingCategories,handleDelete}}>{children}</CategoriesContext.Provider>
}
// And you use it like this:
const App = () => {
return (
<MyCategoriesProvider>
<SomeOtherComponent>
<SomeOtherComponent> <- let's say your PrimarySearchBar is in here somewhere
<SomeOtherComponent>
</MyCategoriesProvider>
)
}
// in PrimarySearchBar you'd do this:
function PrimarySearchBar(props) => {
const {categories} = useContext(CategoriesContext); // you exported this above, remember?
// pass it as a prop to navbar, you could easily put the useContext hook inside of any component
return <NavBar categories={categories}/>
}
// in your category component you could do this:
class Category extends Component {
render() {
// Don't forget, categoriesContext is the thing you exported way up at the top
<CategoriesContext.Consumer>
{({handleDelete}) => {
return <button onClick={() => handleDelete(this.props.category)}>
}}
</CategoriesContext.Consumer>
}
}
編輯:
我看到您正在混合 class 和功能組件,這很好。 您應該查看這篇文章,了解如何在其中任何一個中使用上下文 api - 在功能組件中您通常使用useContext
掛鈎,而在 class 組件中您將使用消費者。
在刪除請求完成后,我會刷新來自服務器的類別列表。
我會這樣做:
<DrawerMenu
classes={classes}
handleDrawerClose={handleDrawerClose}
open={open}
items={/* ... */}
/>
這是一個重要的步驟,因為現在,要刷新呈現的項目列表,您只需傳遞另一個列表。 以這種方式,服務器端邏輯與該組件保持斷開連接。
我不確定您在哪里呈現Category
組件,但假設它呈現在PrimarySearchAppBar
之外,似乎這個 menuItems 可能需要從上層傳遞給組件。 我看到了 2 個解決方案:
const App = props => {
const [categories, setCategories] = React.useState([])
const [menuItems, setMenuItems] = React.useState([])
const fetchCategories = useCallback(()=> {
yourApi.getCategories().then(categories => setCategories(categories))
})
const fetchMenuItems = useCallback(() => {
yourApi.getMenuItems().then(menuItems => setMenuItems(menuItems))
})
useEffect(() => {
fetchCategories()
}, [])
useEffect(() => {
fetchMenuItems()
}, [categories])
const handleDeleteCategory = useCallback(idToDelete => {
yourApi.deleteCategory(idToDelete).then(fetchCategories)
})
return (
<div>
<PrimarySearchAppBar menuItems={menuItems}/>
<Categories categories={categories} onDeleteClick={handleDeleteCategory} />
</div>
)
}
PS。 還有一個很好的鈎子可以讓獲取更容易: https://github.com/doasync/use-promise
我目前使用我發現的 usePromise 掛鈎的自定義版本,因為我添加了一些有趣的功能。 如果您願意,我可以分享它,但我不想在答案中添加噪音。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.