I am trying to integrate redux with reactflow library. When I drag and drop a node on the canvas, user gets a modal where he can enter the node details. After submitting the details, the data attribute of the node object gets updated and the node gets added to the Nodes array in react flow. I am trying to dispatch this node to the redux store but when I call the redux store, it updates the store with the pre defined values/old values of the data attribute instead of the values entered by the user.
Following is the code for the modal which is dispatching the redux action on clicking submit:
import React, { useState, useEffect } from 'react';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import Modal from 'react-bootstrap/Modal';
import {useSelector, useDispatch} from 'react-redux';
import {addNode} from '../flow/flowSlice';
function ScenarioModal(props) {
const [currentNode, setCurrentNode] = useState([]);
const [scenarioValues, setScenarioValues] = useState({});
const [scenarioData, setScenarioData] = useState({
label: "",
type: "Current Scenario",
description: "",
})
const dispatch = useDispatch();
const {nodes, setNodes, nodeId} = props;
useEffect(() => {
setNodes((nds) =>
nds.map((node) => {
if (node.id === nodeId) {
// it's important that you create a new object here
// in order to notify react flow about the change
console.log("Node ID: ", nodeId);
node.data = {
...node.data,
label: scenarioData.label,
type: scenarioData.type,
description: scenarioData.description,
};
}
console.log("New Node: ", node);
setScenarioData({
label:"",
type: "Current Scenario",
description: "",
})
// addNodeIntoStore(node);
return node;
})
);
addNodeIntoStore(nodes);
}, [scenarioValues, setNodes]);
const handleChange = (evt) =>{
const value = evt.target.value;
setScenarioData({
...scenarioData,
[evt.target.name] : value
});
}
const onFormSubmit = e => {
e.preventDefault();
console.log("Scenario Data: ", scenarioData);
console.log(scenarioData);
setScenarioValues(scenarioData);
// addNodeIntoStore(currentNode);
props.handleClose();
}
const addNodeIntoStore = (nodes) =>{
console.log("Add node to store: ", nodes);
nodes.map((node)=>{
console.log("Updated Node: ", node)
if(nodeId === node.id){
dispatch(addNode(node));
}
})
// dispatch(addNode(node));
}
.......
}
Following is my redux slice file which is calling the reducer
export const flowSlice = createSlice({
name:'flow',
initialState : {
nodes: []
},
reducers: {
addNode: (state, action) => {
console.log("Action Payload: ", action.payload);
console.log("Data: ", action.payload.data.label, action.payload.data.type, action.payload.data.description)
if(!_.isEmpty(action.payload)){
state.nodes.push({
...action.payload,
data :{
label: action.payload.data.label,
type: action.payload.data.type,
description: action.payload.data.description,
}
});
}
}
}
})
When I am printing the action payload in the console, it contains the updated values.
But it is updating the store with the old values.
If I directly push the action.payload into the array by using the following code, the application crashes with the error Cannot assign to read only property 'data' of object '#'
state.nodes.push(action.payload);
I am unable to figure out why it is updating the store with the old values when the data attribute coontains updated values.