Computing-Flows

Advanced · 8 min read · Updated Nov 10, 2026

Data Flow: How to Pass, Compute, and Transform Data Between Nodes

Node-based applications are not just about connecting nodes with edges. In a functional workflow editor, each node must be able to receive information, process it, and pass the result to another node. This is what makes a visual workflow more than a diagram.

React Flow provides the tools to build these interactive data-driven applications. With custom nodes, node data, and hooks such as useNodeConnections() and useNodesData(), developers can create workflows where information moves between connected nodes and updates dynamically.

In this guide, we will explore how to pass data between connected nodes in React Flow, calculate values inside a workflow, transform data, and implement conditional branching.

What Is Data Flow in React Flow?

Data flow in React Flow refers to the process of transferring information from one node to another through connected edges.

Each node can perform a specific operation:

  • An input node collects information from users.
  • A processing node receives and transforms data.
  • A decision node evaluates conditions.
  • An output node displays or uses the final result.

For example, consider an automation workflow:

  1. A user enters information into an input node.
  2. The next node processes that information.
  3. A condition node checks the result.
  4. The workflow sends the data through the appropriate connection.
  5. A final node displays the output.

This approach is useful for AI workflow builders, automation platforms, visual programming tools, data processing applications, and interactive diagram editors.

Understanding Node Data and Edges

Before implementing data computation, it is important to understand how React Flow represents information.

A node can store custom information inside its data property:

const initialNodes = [
  {
    id: 'input-1',
    type: 'numberInput',
    position: { x: 100, y: 100 },
    data: {
      label: 'Red',
      value: 120,
    },
  },
];

An edge connects two nodes:

const initialEdges = [
  {
    id: 'edge-1',
    source: 'input-1',
    target: 'color-preview',
    targetHandle: 'red',
  },
];

The source and target properties identify the connected nodes. Handle IDs allow a node to receive or send information through specific connection points.

This becomes especially important when a custom node has multiple inputs or outputs.

1. Create Custom Nodes for Data Input

The first step is to create custom nodes that collect information.

For example, we can build a number input node that accepts values between 0 and 255. These values will later represent the red, green, and blue channels of an RGB color.

import { useCallback, useState } from 'react';
import { Handle, Position, useReactFlow } from '@xyflow/react';

function NumberInput({ id, data }) {
  const [value, setValue] = useState(data.value ?? 0);
  const { updateNodeData } = useReactFlow();

  const handleChange = useCallback(
    (event) => {
      const nextValue = Math.round(
        Math.min(255, Math.max(0, Number(event.target.value)))
      );

      setValue(nextValue);
      updateNodeData(id, { value: nextValue });
    },
    [id, updateNodeData]
  );

  return (
    <div className="number-input">
      <label>{data.label}</label>

      <input
        type="number"
        min="0"
        max="255"
        value={value}
        onChange={handleChange}
        className="nodrag"
      />

      <Handle type="source" position={Position.Right} />
    </div>
  );
}

There are two important concepts in this implementation:

  • Local component state: useState() manages the input value so the field responds immediately to user interaction.
  • Node data updates: updateNodeData() writes the updated value into the node's data object so connected nodes can access it.

Keeping input state locally avoids relying on delayed node-data updates for every keystroke, which can cause cursor or input behavior problems.

2. Update Node Data with useReactFlow()

React Flow provides the useReactFlow() hook to access methods for interacting with the flow instance.

One useful method is updateNodeData(), which updates the data of a particular node.

const { updateNodeData } = useReactFlow();

updateNodeData('input-1', {
  value: 150,
});

By default, the new data is merged with the existing node data. This means you can update a single property without manually copying every other property.

For example, if a node contains:

data: {
  label: 'Red',
  value: 120,
  category: 'color',
}

Updating the value will preserve the other properties.

You can also replace the complete data object by passing the appropriate replacement option:

updateNodeData(
  'input-1',
  { value: 150 },
  { replace: true }
);

This is useful when a node needs to maintain a consistent data structure or when you want to completely replace its current data.

3. Read Data from Connected Nodes

Writing information into node data is only half of the process. The next step is retrieving information from connected nodes.

React Flow provides two important hooks for this purpose:

HookPurpose
useNodeConnections()Finds connections associated with a node or handle
useNodesData()Retrieves the data of one or more nodes by their IDs

The following example shows how to identify connections to a specific target handle:

import {
  useNodeConnections,
  useNodesData,
} from '@xyflow/react';

function ConnectedInput({ handleId }) {
  const connections = useNodeConnections({
    handleType: 'target',
    handleId,
  });

  const sourceId = connections[0]?.source;

  const sourceNode = useNodesData(sourceId);

  const value = sourceNode?.data?.value ?? 0;

  return <div>Received value: {value}</div>;
}

Here is what happens:

  1. useNodeConnections() finds connections attached to the specified target handle.
  2. The first connection provides the source node ID.
  3. useNodesData() retrieves the connected node's data.
  4. The component reads the value and can use it for further calculations.

The example assumes that the handle has at most one connection. If multiple nodes can connect to the same handle, you should define how those values are combined or select the appropriate connection.

4. Build a Node That Computes Data from Multiple Inputs

Now that we can pass and retrieve information, let's create a node that combines multiple values.

Imagine an RGB color generator. It receives three values:

  • Red
  • Green
  • Blue

Each value comes from a separate input node. The color preview node combines them to generate a background color.

A simplified custom node might look like this:

import { useState } from 'react';
import { Handle, Position } from '@xyflow/react';

function ColorPreview() {
  const [color, setColor] = useState({
    r: 0,
    g: 0,
    b: 0,
  });

  return (
    <div
      style={{
        backgroundColor:
          `rgb(${color.r}, ${color.g}, ${color.b})`,
        padding: '24px',
        borderRadius: '12px',
      }}
    >
      <Handle
        type="target"
        position={Position.Left}
        id="red"
      />

      <Handle
        type="target"
        position={Position.Left}
        id="green"
      />

      <Handle
        type="target"
        position={Position.Left}
        id="blue"
      />

      <h3>Color Preview</h3>

      <p>
        RGB({color.r}, {color.g}, {color.b})
      </p>

      <Handle
        type="source"
        position={Position.Right}
      />
    </div>
  );
}

Each target handle has a unique ID. This is essential because the node needs to distinguish between the three incoming values.

To make the example functional, connect each handle to its corresponding source node and update the appropriate color channel whenever that source data changes.

A reusable custom handle component can encapsulate the connection lookup and data subscription:

import { useEffect } from 'react';
import {
  Handle,
  Position,
  useNodeConnections,
  useNodesData,
} from '@xyflow/react';

function CustomHandle({ id, label, onChange }) {
  const connections = useNodeConnections({
    handleType: 'target',
    handleId: id,
  });

  const sourceId = connections[0]?.source;
  const sourceNode = useNodesData(sourceId);

  useEffect(() => {
    onChange(sourceNode?.data?.value ?? 0);
  }, [sourceNode, onChange]);

  return (
    <div>
      <Handle
        type="target"
        position={Position.Left}
        id={id}
      />

      <span>{label}</span>
    </div>
  );
}

You can then use this component inside ColorPreview to update individual color channels.

For production applications, consider handling disconnected inputs, multiple connections, and changes to connection order explicitly.

5. Transform Data Between Connected Nodes

A powerful feature of a data-driven workflow is the ability to transform information as it moves through the graph.

For example, after generating an RGB color, another node can calculate its relative luminance to determine whether the background is light or dark.

The relative luminance calculation can be simplified as:

const luminance =
  0.2126 * color.r +
  0.7152 * color.g +
  0.0722 * color.b;

The result represents the perceived brightness of the color.

A simple classification could be:

const brightness =
  luminance >= 128 ? 'light' : 'dark';

The next node can use this result to choose a suitable text color.

This demonstrates an important workflow concept: a node does not always need to pass its original input forward. It can process the incoming data and generate a completely new output.

The same pattern can be used for:

  • Mathematical calculations
  • Data formatting
  • API response transformation
  • Text processing
  • AI model outputs
  • Image processing
  • Business rule evaluation

6. Implement Conditional Branching in React Flow

Some workflows need to follow different paths depending on the data they receive.

For example, a decision node might evaluate whether a color is light or dark.

Instead of using a single output handle, the node can expose two separate handles:

  • light
  • dark
<Handle
  type="source"
  position={Position.Right}
  id="light"
/>

<Handle
  type="source"
  position={Position.Right}
  id="dark"
/>

Each output represents a different result.

You can structure the node data to store the result associated with each handle:

const outputData = {
  values: {
    light: isLight ? color : null,
    dark: isLight ? null : color,
  },
};

The next connected node can read the relevant output based on the source handle ID.

This allows you to build visual logic such as:

  • If/else conditions
  • Approval and rejection paths
  • User segmentation
  • AI decision workflows
  • Data validation
  • Automated task routing

A key consideration is that conditional routing requires more than simply drawing two edges. Your application must define how downstream nodes interpret the data associated with each output.

7. Best Practices for Building Data-Driven React Flow Applications

When building a complex workflow editor, a consistent data structure and predictable node behavior are essential.

Keep node data structured

Define a predictable format for your node data instead of mixing different structures across nodes.

For example:

const nodeData = {
  inputs: {
    red: 120,
    green: 80,
    blue: 200,
  },
  outputs: {
    color: null,
    brightness: null,
  },
};

This makes it easier for other nodes to understand the information they receive.

Use unique handle IDs

When a node contains multiple handles of the same type, assign a unique ID to each one.

This allows your application to identify which input or output is being used.

Separate UI state from computed data

Use local React state for interactive fields when immediate updates are important. Use node data for information that other nodes need to access.

Handle disconnected nodes

A workflow can change at any time. Nodes may be disconnected, deleted, or connected to different sources.

Always account for missing connections and undefined data.

Avoid unnecessary computations

Large workflows can contain many connected nodes. Keep calculations efficient and avoid triggering expensive operations unnecessarily.

For more complex applications, consider separating workflow execution logic from the visual representation of the graph.

8. Real-World Applications of React Flow Data Computation

Computing data directly inside React Flow opens the door to building more advanced visual applications.

Here are some practical examples:

ApplicationHow data flows
AI Workflow BuilderPrompt input → AI processing → Output
Marketing AutomationLead data → Conditions → Campaign actions
Data VisualizationData source → Transformation → Chart
Form BuilderUser input → Validation → Submission
Decision EngineInput values → Business rules → Branching
Color GeneratorRGB inputs → Color calculation → Preview
Automation PlatformTrigger → Processing → Conditional actions

These examples demonstrate how React Flow can be used as the foundation for interactive applications rather than simply displaying static diagrams.

9. Build Advanced Workflow Editors with VisualFlow

Building a data-driven workflow editor from scratch requires more than connecting nodes. You need a reliable node architecture, custom handles, data management, conditional routing, and a user-friendly editing experience.

VisualFlow provides React Flow examples and ready-to-use templates that can help developers explore and build advanced node-based applications.

You can use these examples as a starting point for creating:

  • AI agent builders
  • Visual automation editors
  • Data processing workflows
  • Marketing automation systems
  • Interactive diagram editors
  • Custom node-based applications

Explore VisualFlow to discover practical React Flow examples and workflow templates that can help accelerate your development process.

Conclusion

Computing data between connected nodes is one of the most important concepts when building functional applications with React Flow.

By combining updateNodeData(), useNodeConnections(), and useNodesData(), developers can create workflows where nodes exchange information, transform values, and make decisions based on connected data.

Once you understand these concepts, you can move beyond static diagrams and build interactive workflow editors, automation platforms, AI builders, and visual programming applications.

The key is to maintain a consistent data structure, handle connections carefully, and keep each node's responsibilities clearly defined.

Interactive colour flow graphOpen in New TabCreating Custom NodeOpen in New Tab