Hi @waseem-medhat! This is a great question.
In practice, in my “real world” proprietary projects, I’m usually using React to orchestrate the interactivity (state management), then using D3 for the visualization logic. So, for example, state would be tracked with React (typically via useState
), then the state as well as the state setter functions are passed into the D3 logic.
One great thing about this approach is that it scales well to development teams with multiple frontend developers. I’ve often collaborated with folks who know React but not D3, and this approach allowed them to, for example, work on the state and data fetching logic in such a way that it was totally decoupled from the D3 logic. I’ve also worked in teams where another developer knows D3 well, but does not know React. This approach of decoupling the logic allowed them to spin up and be productive quickly by just editing the D3 logic, without any awareness of the outer layers of the React code.
The approach is also good for an organization, because let’s say a new project comes along in 6 months time where it’s done in, say, Svelte and not React. The future team could utilize the isolated D3 logic in a straight up copy-paste migration without having to re-code any of the visualization rendering logic. So in this sense the portability can be useful outside a teaching context.
For new projects, if there is any need for traditional non-SVG UI elements in addition to the visualization at all, I like to start with React. That way the team can fully leverage React for what it’s best at, the non-D3 UI that surrounds the visualization, and the state management.
For new projects that are just visualizations and no surrounding UI, it does make sense to start without using any framework. You’d just need to roll your own state management solution. In cases like this, I do roll my own state management solution, but it’s based on the API of useState
, so that the D3 logic can still be compatible with React should you choose to adopt it in the future.
Here’s an example implementation of state management that can be used when React is not used, which has an API compatible with const [state, setState] = useState({})
:
import { viz } from './viz';
let state = {};
const container = document.getElementById('viz');
const render = () => {
viz(container, { state, setState });
};
const setState = (next) => {
state = next(state);
render();
};
render();