javascript - 当像 FSM 和 useEffect 一样使用时,React 状态更新是否按顺序发生?

标签 javascript reactjs typescript

我正在尝试在 ReactJS 功能组件中构建一个简单的 FSM(有限状态机)。我在找at this这指定他们可以异步执行,其次他们可以合并状态更改。

在类组件中,您可以使用双参数 setState() 方法链接状态更改。但是 useState() Hook 中没有该功能。

基本上我想知道是否可以根据指定的行为创建 FSM?我正在尝试尽可能地缩小示例

我对 setter 的使用做了一些限制,即它只会在以下情况下执行:

  • 一个状态处理函数
  • 一个事件处理程序(甚至是有限的)
  • 一个状态可以有自己的子状态,它是另一个状态存储(基本上是附加参数,只能由上述两个函数读取或写入)

无论如何,我设置了我的初始状态,并且我有一个单独的 useEffect Hook ,如下所示

const [fsmState, setFsmState] = useState(States.Initial)
useEffect(() => {
  stateHandlers[fsmState]();
}, [fsmState]);

States 是一个enum

enum States {
  Initial,
  Unauthenticated,
  Authenticated,
  Processing
}

我定义stateHandlers如下:

  const stateHandlers: {
    [key in States]: () => void | Promise<void>;
  } = {
    [States.Initial]: async () => { 
      // this may load authentication state from a store, 
      // for now just set it to Unauthenticated
      setFsmState(State.Unauthenticated);
    },
    [States.SigningIn]: async () => { 
      const authToken = await loginToServer(signInState));
      if (authToken.isValid()) {
        setFsmState(State.Authenticated);
      } else {
        setFsmState(State.Unauthenticated);
      }
    },
    [States.Authenticated]: () => { },
    [States.Unauthenticated]: () => { },
  }

对于事件处理程序,例如登录 我这样做(这基本上就是我问这个问题的原因。

const signinAsync = async (username: string, password: string) => {
  if (fsmState !== States.Unauthenticated) throw Error("invalid state");
  // would these two get set in order?
  setSignInState({username,password})
  setFsmState(State.SigningIn);
}

如前所述,双参数版本不可用,所以我不能这样做

setSignInState({username,password},
  () => { setFsmState(State.SigningIn) } )

我只是想要一个简单的 TSX 实现来避免添加额外的库。但是,在我学习 TypeScript/React 的过程中,我仍在编写此代码。

最佳答案

是的,这是可能的。事实上,有一个著名的 FMS 库叫做 xstate https://github.com/davidkpiano/xstate .

更新状态将始终是异步的,因为这就是它的工作方式并且是正确的。在您的状态机处理程序中,您只需要确保转换是正确的。我已经可以看出您的实现已经朝着正确的方向前进。

const signinAsync = async (username: string, password: string) => {
  if (fsmState !== States.Unauthenticated) throw Error("invalid state");
  // would these two get set in order?
  setSignInState({username,password})
  setFsmState(State.SigningIn);
}

无法保证哪一个会先发生。您的实现应该处理所有情况,无论是 setSignInState 还是 setFsmState 先发生。这两个 Action 应该是独立的。如果你需要两者都在一个系列中,那么你需要将它们链接在回调或其他东西中。例如,使用 setState,您可以将第二个参数作为回调传递,该回调将在状态更新后调用。

this.setState({ title: event.target.value }, function() {
    this.validateTitle(); // thid will happen after state update
  });

关于javascript - 当像 FSM 和 useEffect 一样使用时,React 状态更新是否按顺序发生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65855083/

相关文章:

javascript - React 中的登录身份验证和 Laravel 不记录日志

javascript - 通过拖动鼠标对滚动 div 使用react?

typescript 装饰器作为混合?

javascript - 使用 JsDoc 转换 Typescript

javascript - 如何测试我是否已加载我的 JSON - Angular 2

javascript - react BaseTable rowSpan "flickering"

javascript - 为什么createObjectURL构造的图像宽度为0?

javascript - 模拟 sinon 中的当前时间

javascript - Jquery 检查是否有父 div 有滚动条

javascript - React Hook "useContext"在函数 "age"中调用,该函数既不是 React 函数组件,也不是自定义 React Hook 函数