Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 第一次点击按钮有一种奇怪的行为_Scala_Scala.js_Scala Cats_Scalajs React - Fatal编程技术网

Scala 第一次点击按钮有一种奇怪的行为

Scala 第一次点击按钮有一种奇怪的行为,scala,scala.js,scala-cats,scalajs-react,Scala,Scala.js,Scala Cats,Scalajs React,我正在使用一个待办事项列表应用程序 scalajs 猫(自由单子),和 鳞片反应 当我使用下面的代码这样的简单模型时,一切都像预期的那样工作 class-TodoModel(){ 私有对象状态{ var todos=序列空[Todo] def mod(f:Seq[Todo]=>Seq[Todo]):回调={ val newTodos=f(todos) 回调(todos=newTodos) } } def add(t:Todo):Callback=State.mod(\+t) def todo

我正在使用一个待办事项列表应用程序

  • scalajs
  • 猫(自由单子),和
  • 鳞片反应
当我使用下面的代码这样的简单模型时,一切都像预期的那样工作

class-TodoModel(){
私有对象状态{
var todos=序列空[Todo]
def mod(f:Seq[Todo]=>Seq[Todo]):回调={
val newTodos=f(todos)
回调(todos=newTodos)
}
}
def add(t:Todo):Callback=State.mod(\+t)
def todos:Seq[Todo]=State.todos
}
一旦我使用猫的免费单子,我会有一种奇怪的行为。第一次单击总是插入两个待办事项条目。之后的每一次点击都像预期的那样工作。请看下面的图片

这里怎么了

导入cats.free.free
进口猫。免费。免费。liftF
导入japgolly.scalajs.react_
导入japgolly.scalajs.react.vdom.html}
val interpet:TodoModelOp~>Id=new(TodoModelOp~>Id){
val todos=scala.collection.mutable.ArrayBuffer.empty[Todo]
def apply[A](fa:TodoModelOp[A]):Id[A]=fa匹配{
案例添加(todo)=>todo+=todo;()
case Todos()=>Todos.toSeq
}
}
}
类TodoModel(){
导入cats.instances.list_
导入cats.syntax.traverse_
导入FreeTodoModelOps_
def add(t:Todo):回调={
def程序:TodoModelOpF[单位]=用于{
_ 
$.modState(s=>State(s.todos:+t))>>
$.props.flatMap(P=>P.model.add(t))
def渲染(S:状态)=

在您的第一个代码片段中有一个bug:

这里有一个变量
todos
(inpure),您在纯上下文中访问该变量:

def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
  val newTodos = f(todos)
  Callback(todos = newTodos)
杂质应该在
回调中
。即使在回调之外读取变量也是不安全的,因此应该:

def mod(f: Seq[Todo] => Seq[Todo]): Callback =
  Callback(todos = f(todos))
(参见scalajs react,这是一个安全使用变量的示例。)

其次,关于您的较大代码段,scalajs react对FP非常友好,但这是一种非常非常规的使用方式,并且存在一些重大问题:

  • stateTranslator.interpet
    不是引用透明的;它的基础是共享的全局状态。FP测试失败。不再是合法的自然转换
  • 您分别跟踪两组相同的状态:组件状态和
    TodoModel
    中的状态(不纯,未通过FP测试)。这种方法不仅是多余的,而且存在两种状态不同步的风险,而且还会降低组件的可重用性;想象一下,您决定在同一屏幕上为相同的数据绘制两次该组件-它们将不同步。最好使组件保持无状态和纯状态
  • 如果要将自由结构转换为组件效果,最好将其转换为状态单子,请参见示例

你正在学习免费的Monad和ScalaJ react,这真是太棒了。FP将使你的整个程序真的、真的很容易推理并防止令人困惑的意外行为,但你必须不走弯路,确保你所有的代码都是纯的。任何杂质都会使整个堆栈一路上升对于入口点不纯,并从这些层中删除这些好的可靠FP属性。我建议使用上面的点作为起点,使所有内容尽可能纯净,然后我想你会发现缺陷消失了,或者至少很容易检测到。干杯

在你的第一个片段中有一个缺陷:

这里有一个变量
todos
(inpure),您在纯上下文中访问该变量:

def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
  val newTodos = f(todos)
  Callback(todos = newTodos)
杂质应该在
回调中
。即使在回调之外读取变量也是不安全的,因此应该:

def mod(f: Seq[Todo] => Seq[Todo]): Callback =
  Callback(todos = f(todos))
(参见scalajs react,这是一个安全使用变量的示例。)

其次,关于您的较大代码段,scalajs react对FP非常友好,但这是一种非常非常规的使用方式,并且存在一些重大问题:

  • stateTranslator.interpet
    不是引用透明的;它的基础是共享的全局状态。FP测试失败。不再是合法的自然转换
  • 您分别跟踪两组相同的状态:组件状态和
    TodoModel
    中的状态(不纯,未通过FP测试)。这种方法不仅是多余的,而且存在两种状态不同步的风险,而且还会降低组件的可重用性;想象一下,您决定在同一屏幕上为相同的数据绘制两次该组件-它们将不同步。最好使组件保持无状态和纯状态
  • 如果要将自由结构转换为组件效果,最好将其转换为状态单子,请参见示例

你正在学习免费的Monad和ScalaJ react,这真是太棒了。FP将使你的整个程序真的、真的很容易推理并防止令人困惑的意外行为,但你必须不走弯路,确保你所有的代码都是纯的。任何杂质都会使整个堆栈一路上升到入口点不纯净,并从这些层中删除那些好的可靠FP属性。我建议使用上面的点作为起点,使一切尽可能纯净,然后我想你会发现缺陷消失了,或者至少很容易检测到。干杯

谢谢!(1)
状态解释器应该模拟一个外部存储器。(2)你是对的。我将只在
TodoModel
中的状态中添加TODO,并将其复制到组件状态:
$.props.flatMap(P=>P.model.add(t))>$.modState((S,P)=>S.copy(P.model.todos))
(3)关于状态monad:我找不到一种方法可以访问道具和组件状态,如(2)所示。当然,错误在更改后消失:-)。我非常喜欢FP,但仍然是初学者。很高兴听到bu