英文:
How to notify an event without props from descendant to ancestor component
问题
我有一个组件(<Grid>
),其中包含n个嵌套组件
<Grid>
<Header>
<Toolbar>
...
</Toolbar>
<Filters>
<Form>
...
</Form>
</Filters>
</Header>
<Body>
<Datazone>
...
</Datazone>
<Summary>
...
</Summary>
</Body>
<Footer>
...
</Footer>
</Grid>
我需要创建一个组件(<MagicButton>
),可以将其放置在<Grid>
树的任何位置。无论放置在树的哪个位置,按下它后应该执行某些操作,然后向<Grid>
组件“通知”事件。
先决条件:我不想完全使用属性传递,所以我考虑了以下解决方案:
在上下文中包装<Grid>
,并传递一个函数,该函数可以通过上下文值通知/更新<Grid>
。这个函数是由使用上下文useContext
的<MagicButton>
组件“触发”的。
这个方法是否正确?
如果是的话,是否可能通过上下文提供<MagicButton>
组件,而不是“导入”,然后将<MagicButton>
组件添加到网格的子组件<Toolbar>
中,例如?
如果不是,是否有其他通知祖先组件的方法(显然不使用属性传递)?
<GridPersistenceStateContext.Provider value={NotificationFunction}>
<Grid>
<Header>
<Toolbar>
<MagicButton />
</Toolbar>
<Filters>
<Form>
...
</Form>
</Filters>
</Header>
<Body>
<Datazone>
...
</Datazone>
<Summary>
<MagicButton />
</Summary>
</Body>
<Footer>
<MagicButton />
</Footer>
</Grid>
</GridPersistenceStateContext.Provider>
“自定义事件”方法是否代表可行的替代方法?
“自定义事件”是否会对正常的React生命周期造成问题?
英文:
I've a component (<Grid>
) with n
nested components
<Grid>
<Header>
<Toolbar>
...
</Toolbar>
<Filters>
<Form>
...
</Form>
</Filters>
</Header>
<Body>
<Datazone>
...
</Datazone>
<Summary>
...
</Summary>
</Body>
<Footer>
...
</Footer>
</Grid>
I need to create a component (<MagicButton>
) that can be placed everywhere into the <Grid>
tree, wherever it is placed along the tree, when it's pressed it should do something and then "notify" an event to the <Grid>
component.
prerequisite: I don't want to use props drilling at all, so I've thought of this solution:
To wrap the <Grid>
in a context and pass a function that can notify/update the <Grid>
in the context value. This function is "tirggered" from a <MagicButton>
component that use the context useContext
is this approch correct?
If yes, is it possible to provide the <MagicButton>
component through/by the context instead of "import" then <MagicButton>
component into a grid's child component <Toolbar>
e.g.
If not, is there another approch to notify to an anchestor component (without no props drilling obviously)
<GridPersistenceStateContext.Provider value={NotificationFunction}>
<Grid>
<Header>
<Toolbar>
<MagicButton />
</Toolbar>
<Filters>
<Form>
...
</Form>
</Filters>
</Header>
<Body>
<Datazone>
...
</Datazone>
<Summary>
<MagicButton />
</Summary>
</Body>
<Footer>
<MagicButton />
</Footer>
</Grid>
<GridPersistenceStateContext.Provider />
Does the "custom event" approch reppresent a viable alternative?
can "custom events" cause problems to the normal react lifecicle?
答案1
得分: 1
-
上下文提供了一种在组件之间共享这些值的方式,而不必显式地通过树的每一级传递prop。这是正确的方法。
-
可以通过上下文提供
<MagicButton>
组件,而不是在每个地方都导入<MagicButton>
组件。我们可以使用SomeContext.Consumer
,这是一种较旧的读取上下文的方式。这样我们就可以获取MagicButton
组件并渲染它。
例如:
MagicButton.tsx
:
import React from 'react';
export const MagicButton = (props: any) => <button {...props}>magic button</button>;
context.ts
:
import React from 'react';
export const GridPersistenceStateContext = React.createContext<{
notify: (from: string) => void;
MagicButton: (props: any) => JSX.Element;
}>(null!);
import React from 'react';
import { GridPersistenceStateContext } from './context';
import { MagicButton } from './MagicButton';
const Toolbar = ({ children }: React.PropsWithChildren) => <div>{children}</div>;
export default function App() {
const notificationFunction = (from: string) => {
console.log('notified from: ', from);
};
return (
<div className="App">
<GridPersistenceStateContext.Provider value={{ notify: notificationFunction, MagicButton }}>
<div className="Header">
<Toolbar>
Toolbar:
<GridPersistenceStateContext.Consumer>
{({ MagicButton, notify }) => (
<MagicButton
onClick={() => {
notify('toolbar');
}}
/>
)}
</GridPersistenceStateContext.Consumer>
</Toolbar>
</div>
<div className="Body">
<div className="Summary">
Summary:
<GridPersistenceStateContext.Consumer>
{({ notify, MagicButton }) => (
<MagicButton
onClick={() => {
notify('summary');
}}
/>
)}
</GridPersistenceStateContext.Consumer>
</div>
</div>
</GridPersistenceStateContext.Provider>
</div>
);
}
英文:
-
Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree. It's the correct approach.
-
It's possible to provide the
<MagicButton>
component through the context instead ofimport
the<MagicButton>
component everywhere. we can useSomeContext.Consumer
, an older way to read context. So that we can get theMagicButton
component and render it.
E.g.
MagicButton.tsx
:
import React from 'react';
export const MagicButton = (props: any) => <button {...props}>magic button</button>;
context.ts
:
import React from 'react';
export const GridPersistenceStateContext = React.createContext<{
notify: (from: string) => void;
MagicButton: (props: any) => JSX.Element;
}>(null!);
import React from 'react';
import { GridPersistenceStateContext } from './context';
import { MagicButton } from './MagicButton';
const Toolbar = ({ children }: React.PropsWithChildren) => <div>{children}</div>;
export default function App() {
const notificationFunction = (from: string) => {
console.log('notified from: ', from);
};
return (
<div className="App">
<GridPersistenceStateContext.Provider value={{ notify: notificationFunction, MagicButton }}>
<div className="Header">
<Toolbar>
Toolbar:
<GridPersistenceStateContext.Consumer>
{({ MagicButton, notify }) => (
<MagicButton
onClick={() => {
notify('toolbar');
}}
/>
)}
</GridPersistenceStateContext.Consumer>
</Toolbar>
</div>
<div className="Body">
<div className="Summary">
Summary:
<GridPersistenceStateContext.Consumer>
{({ notify, MagicButton }) => (
<MagicButton
onClick={() => {
notify('summary');
}}
/>
)}
</GridPersistenceStateContext.Consumer>
</div>
</div>
</GridPersistenceStateContext.Provider>
</div>
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论