react-tracked icon indicating copy to clipboard operation
react-tracked copied to clipboard

How to get the original state

Open marcinkieruzel opened this issue 1 year ago • 1 comments

Hi, I've recently experienced an issue with React Track. Perhaps its more about understanding the library and proxies than a real problem but – In some cases I want to have the up to date context event if it's not rendered in current component. For example in useEffect hook or events. Hence an onClick event in PersonFamilyName. It will always give me an "old" value of firstName. How can I get up to date context in this circumstances?

import React, {
  useReducer,
  useRef,
  useEffect,
  Reducer,
} from 'react';

import { createContainer, getUntrackedObject } from 'react-tracked';

const initialState = {
  firstName: 'Harry',
  familyName: 'Potter',
};

type State = typeof initialState;
type Action =
  | { type: 'setFirstName'; firstName: string }
  | { type: 'setFamilyName'; familyName: string };

const reducer: Reducer<State, Action> = (state, action) => {
  switch (action.type) {
    case 'setFirstName':
      return { ...state, firstName: action.firstName };
    case 'setFamilyName':
      return { ...state, familyName: action.familyName };
    default:
      throw new Error('unexpected action type');
  }
};

const { Provider, useTracked } = createContainer(
  () => useReducer(reducer, initialState),
  { concurrentMode: true },
);

const PersonFirstName = () => {
  const [state, dispatch] = useTracked();
  const renders = useRef(1);
  
  useEffect(() => {
    renders.current += 1;
  });




  return (
    <div>
      First Name: {Math.random()}
      <input
        value={state.firstName}
        onChange={(event) => {
          dispatch({ type: 'setFirstName', firstName: event.target.value });
        }}
      />
      (renders:{renders.current})
    </div>
  );
};

const PersonFamilyName = () => {
  const [state, dispatch] = useTracked();
  const renders = useRef(1);
  
  useEffect(() => {
    console.log("Test FamilyName")
    renders.current += 1;
  });


  

  return (
    <div>
      Family Name: {Math.random()}

      <button onClick={() => {
        console.log("I want to get the actual state", state.firstName)
        console.log("I want to get the actual state", getUntrackedObject(state))
      }}>Click</button>

      <input
        value={state.familyName}
        onChange={(event) => {
          dispatch({ type: 'setFamilyName', familyName: event.target.value });
        }}
      />
      (renders:{renders.current})
    </div>
  );
};

const ReactTracked = () => (
  <Provider>
    <PersonFirstName />
    <PersonFamilyName />
  </Provider>
);

export default ReactTracked;```

marcinkieruzel avatar Jun 01 '23 16:06 marcinkieruzel

In some cases I want to have the up to date context event if it's not rendered in current component.

I don't think it's an issue with react-tracked. It's how useState (useReducer) works. I mean, it will behave the same with bare context.

What you want is probably a "global state" and in such cases, you may want to try zustand (with or without react-tracked), or jotai, or valtio.

dai-shi avatar Jun 01 '23 23:06 dai-shi

Closing as stale.

dai-shi avatar Mar 02 '24 01:03 dai-shi