0

This will have something to so with async but I can't get to the bottom of it.

Problem: when I log my global state object to console, it is not returning all the properties. Despite the fact that the missing property can be logged to console independently.

When I log state.workflow (the overall object that stores the global state) I get:

{
    "workflow_id": "", // Never updates
    "workflow": [...]  // Always updates
}

But if I separately log (state.workflow_id) it gives me the value.

My reducer:

export default function workflowReducer(state, action) {
  switch (action.type) {
    case 'SET_WORKFLOW_ID':
      return action.payload;
    case 'SET_WORKFLOW_NAME':
      return action.payload;
    case 'ASSIGN_WORKFLOW':
      return action.payload;
    case 'ADD_NODE':
      return {workflow: [...state.workflow, action.payload]};
    default:
      return state;
  }
}

My context (the dispatches run on init):

export const WorkflowProvider = ({children}) => {
  const [state, dispatch] = useReducer(workflowReducer, initialState);
  const [initialized, setInitialized] = useState(false);
  useEffect(() => {
    if (initialized) return;
    getStoredCanvas().then((response) => {
      setInitialized(true);
      dispatch({
        type: 'SET_WORKFLOW_ID',
        payload: {
          ...initialState,
          workflow_id: response.data.workflow_id
            ? response.data.workflow_id
            : JSON.stringify(mintGuid()),
        },
      });
      dispatch({
        type: 'ASSIGN_WORKFLOW',
        payload: {
          ...initialState,
          workflow: response?.data.elements,
        },
      });
    });
  }, [dispatch, initialized]);

  return (
    <React.Fragment>
      {initialized && (
        <WorkflowContext.Provider value={{state, dispatch}}>{children}</WorkflowContext.Provider>
      )}
    </React.Fragment>
  );
};

My state:

const initialState = {
  workflow_id: '',
  workflow_name: undefined,
  workflow: [],
};

My logging method:

const {state} = useContext(WorkflowContext);
const sendRequest = useCallback( () => {
    if (isSending) return;
    setIsSending(true);
    console.group('%c Data to [Workflow] EP ', 'background: #222; color: #bada55');
    console.log(state);
    console.groupEnd();
    if (isMounted.current) setIsSending(false);
  }, [isSending, state]);

Thank you for any help.

thomasbishop
  • 73
  • 1
  • 8
  • Why is `sendRequest` using `async`? I dont see any promise handling being done. – morganney Mar 09 '22 at 14:10
  • Unrelated functionality, irrelevant to question. Need it for when it is making an API request (not shown). Could be a log without async. – thomasbishop Mar 09 '22 at 14:12
  • You start the question by stating you think it has something to do with async, but then you omit some async code? Ok. – morganney Mar 09 '22 at 14:14
  • I mean that console logs are synchronous whereas I believe (not sure) the reducer is updated async. Have updated. – thomasbishop Mar 09 '22 at 14:16

1 Answers1

0

In case this helps some other hapless soul. The issue arose from my seeking to update the two properties independently of one another, in two dispatch methods rather than a single dispatch covering both properties. Thus

The context and initializers:

export const WorkflowProvider = ({children}) => {
  const [state, dispatch] = useReducer(workflowReducer, initialState);
  const [initialized, setInitialized] = useState(false);
  useEffect(() => {
    if (initialized) return;
    getStoredCanvas().then((response) => {
      setInitialized(true);
      dispatch({
        type: 'SET_PROPERTY',
        payload: {
          ...initialState,
          workflow: response?.data.workflow,
          workflow_id: response?.data.workflow_id || mintGuid(),
        },
      });
    });
  }, [dispatch, initialized]);

  return (
    <React.Fragment>
      {initialized && (
        <WorkflowContext.Provider value={{state, dispatch}}>{children}</WorkflowContext.Provider>
      )}
      {/* TODO : Add error handling */}
    </React.Fragment>
  );
};

export default WorkflowProvider;

The reducer:

export default function workflowReducer(state, action) {
  switch (action.type) {
    case 'ADD_EDGE':
      return action.payload;
    case 'SET_PROPERTY':
      return action.payload;
    case 'ADD_NODE':
      return {
        ...state,
        workflow: [...state.workflow, action.payload],
      };
    default:
      return state;
  }
}
thomasbishop
  • 73
  • 1
  • 8