NEED FEEDBACK - Feature Idea -- Exportable GraphinProvider & useGraphin() react hook to access data from GraphinContext
See original GitHub issueHi Graphin team & community, I would like your opinion on this feature proposal for the library.
Problem Statement
Currently, there is no way to access the GraphinContext
data outside of the <Graphin>
component.
This is because @antv/graphin
does not expose as an exportable GraphinProvider
component.
Example / Scenario 1
Imagine I have a component called <NetworkTopologyViewer>
which is responsible for setting up my <Graphin>
component along with custom behavior
/**
* @description
* Renders a Graph wrapped in a custom container
* and also sets up custom node behavior
*/
const NetworkTopologyViewer = () => {
const { graph } = React.useContext(GraphinContext); //❗ does not work. GraphinContext is not inside of a Provider
const handleNodeClick = e => {
console.log(e.item.getModel();
makeAPICall(e.item.getModel()))
}
// ❗ Cannot setup custom node behavior here because `graph` cannot be grabbed from context above
graph.on('node:click', handleNodeClick)
return (
<Card title="Network Topology">
<Graphin {...GraphinProps....}>
<!- 😢 context data is only available in here. -->
</Graphin>
<Card>
)
}
This is a live code example of what I’m trying to achieve above, which is to define a handleClick
event for when a node in my graph gets clicked.
Proposal
Expose a useGraphin
hook, which allows us get & set data from the GraphinContext
.
// --------------------App.tsx--------
// Initialize with no data
import { GraphinProvider } from '@antv/graphin'
const graphinContextData = {...};
<GraphinProvider>
<NetworkTopologyViewer />
</GraphinProvider>
// ---------OR initialize with data --------------
const graphinContextData = {...};
<GraphinProvider value={graphinContextData}>
<NetworkTopologyViewer />
</GraphinProvider>
/**
* @description
* Renders a Graph wrapped in a custom container
* and also sets up custom node behavior
*/
const NetworkTopologyViewer = () => {
const { graph, api} = useGraphin(); ✅ does not error because this component is inside a Provider in a parent component
const handleNodeClick = e => {.....})
graph.on('node:click', handleNodeClick) // I can setup my node behavior outside of <Graphin> 🎉
return (
<Card title="Network Topology">
<Graphin {...GraphinProps....}/>
<Card>
)
}
Benefits
- adds more flexibility to the API
const TopologyViewer = () => { const { graph, apis, isGraphinReady } = useGraphin(); if (isGraphinReady === false) { return <SomeSkeletonLoader />; // skeleton component for good user experience https://ant.design/components/skeleton/ } return ( <Graphin> ...</Graphin> ) }
- no more need to import
GraphinContext
since theuseGraphin()
hook can get or set data from theGraphinContext
- you would be able to use the
useGraphin()
hook inside of other hooks custom hooks.- This would enable us to keep our component code a lot simpler; business logic could be encapsulated in inside custom hooks thanks to the help of
useGrapin()
.
function myCustomHook(){ const {graph, apis} = useGraphin() // I can easily put business logic code here .......I can manipulate the state of my graph & Graphin context here. // this would could update GraphinProvider & update areas of my user interfance }
- This would enable us to keep our component code a lot simpler; business logic could be encapsulated in inside custom hooks thanks to the help of
- eliminates the need to have custom wrappers and containers. With the
useGraphin
hook, I can access all the data I need from any component wrapped by theGraphinProvider
.
- you would be able to use the
- easier to write test for the code
Steps required to implement useGraphin
in @antv/graphin
- We would need to make
GraphinProvider
component & make it exportable to allow user’s to wrap their component(s) with `GraphinProvider- By default if no data is passed into
GraphinProvider
the data will be empty, but after<Graphin>
component loads, it will update theGraphinProvider
’s context data
- By default if no data is passed into
const graphinContextData = {...};
<GraphinProvider>
<NetworkTopologyViewer />
</GraphinProvider>
// ---------OR initialize with data --------------
const graphinContextData = {...};
<GraphinProvider value={graphinContextData}>
<NetworkTopologyViewer />
</GraphinProvider>
Example Fake Demo
Demo 1: https://stackblitz.com/edit/react-ts-cuhbx2?file=App.tsx
Demo2:
This demonstrates the hook pattern I’m describing (to grab data from context data with hook), which is a common API pattern. This example show a useAuth()
to demonstrate the concept described broadly.
References
This react pattern of using a hook to get & set data from the context is often called the “Action hooks pattern”. It’s nice and flexible & quite popular in newer react libraries like react-query
, react-router
etc.
Tanner Linsley (creator of react-query
) talking about this pattern:
Kent C Dodds (creator or react-testing-library)
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:10 (5 by maintainers)
Top GitHub Comments
It’s a nice idea! Currently for motif, we are just storing the ref from Graphin and passing it through to the other widget components using a provider. The other components can then
useContext
and have access to the full G6 api.A
useGraphin
would help simplify things.I agree that deprecate class component will embrace more features of React 18, but for now, it might not be done in this version, considering that some of the users still depend on class lifecycle to do something, in this version using id might be enough for users, and for break change (like converting Graphin to function component), may happen in a new version like Graphin 3?