lihongwang 创建的主题
  • React 71 0 1 发布

    Hook是React16.8的新增特性。它可以让我们在不使用类语法(class)的情况下编写有状态组件(Stateful Component)。

    Hook将React哲学(显式数据流和组合)引入到组件内部,而不仅仅是组件之间。使用这一方案可以让组件内部的代码逻辑更为清晰条理化。

    下面首先通过对class组件的改造来了解Hook的适用法。

    首先是一个简单的SubmitButton组件:

    import React, { Component } from "react"; export default class SubmitButton extends Component { constructor(props) { super(props); this.state = { text: "click me!" }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(() => { return { text: "loading..." }; }); setTimeout(() => { this.setState(() => ({text: "submited!"})) }, 3000); } render() { const { text } = this.state; return (<button onClick={this.handleClick}>{text}</button>); } }

    SubmitButton组件,通过自己的state管理显示文本。

    import React, { Component } from 'react'; import Button from "./SubmitButton" class FormComponent extends Component {

    state = {
    name: 'honwlee',
    age: 33
    }

    handleNameChange = (firstName) => {
    this.setState({ firstName })
    }

    handleLastNameChange = (lastName) => {
    this.setState({ lastName })
    }
    handleAgeChange = (age) => {
    this.setState({ age })
    }
    onSubmit = (e) => {
    e.preventDefault();
    }

    render () {
    return (
    <React.Fragment>
    <form>
    <input
    name="name"
    type="text"
    onChange={(e) => this.handleNameChange(e.target.value)}
    value={this.state.name}
    />

    &lt;input name="age" type="number" onChange={(e) =&gt; this.handleAgeChange(e.target.value)} value={this.state.age} /&gt; &lt;Button&gt;&lt;/Button&gt; &lt;/form&gt; &lt;/React.Fragment&gt; )

    }
    };
    export default FormComponent;

  • 软件开发 106 0 1 发布

    Perl语言的设计者Larry Wall在《Programing Perl》中提到一个有趣的概念:优秀的程序员具有三大美德---懒惰、急躁以及傲慢。

    懒惰是避免机械式的重复劳作,急躁是不忍受低效的执行过程,傲慢嘛,不放过任何运行中出现的错误。

    感觉还可以加一点:宅,耐得住学习的寂寞。

    下面是编程方面的一些点的记录,方便后续扩展加深学习:

    关于作用域

    在编程中最为让人头疼的事中,命名往往是其中之一。给变量和函数取一个合适的名字,不仅能提高程序的可读性,而且还能减少程序的bug数量。

    怎样命名是一件很考验程序员功底的事情,而怎样避免名字冲突,是程序员必须解决的一个问题。小型项目,也许给名字加上一些特殊规则,比如名字中加入开发者名字或者引入命名申请制等,就能解决,

    但是随着程序规模的扩大,开发人员的增加,上面的解决方案就不太合适,而且有时还会导致代码变得越加混乱,难以管理和控制。

    没有更好的方案了吗?于是作用域的概念开始提出,并逐渐成为了主流方案。

    作用域是指名字的有效范围。将名字限制在有限的范围之内,在范围之外的重名不受影响。

    总体上,作用域可分为全局作用域、动态作用域和静态作用域。

  • Ruby 70 0 1 发布

    “如果一个东西,走路像鸭子,叫声也像鸭子,那么它就是鸭子”。这个就是Duck Tying的通俗解释。

    在ruby中,对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。

    也就是说对象类型是根据对象能作什么即对象的行为(method)来决定,而不是其类。

    Dock Typing Wiki

    下面通过实例来加深理解:

    想象一下小黄鸭的制作流程

    Worker制作小黄鸭模具。Cooker将塑料倒入模具烘制塑料小黄鸭。Painter给小黄鸭上色QualityAssurance对小黄鸭进行质保检查。Packager打包小黄鸭。 class Duck def prepare(workers) workers.each do |worker, index| case worker when Moulder worker.pour_mold(self) when Cooker worker.cook_duck(self) when Painter worker.paint_duck(self) when QualityAssurance worker.test_duck(self) when Packager worker.package_duck(self) end end end end

    上面的代码,造成了互相依赖的问题,Dock需要知道worker以及各worker的具体实现细节(work的类以及work的prepare方法)。

    这样的代码,高度耦合,不利于后续的扩展与维护。

    下面使用Dock Typing的概念对其重构:

    class Duck def prepare(workers) workers.each{ |worker| worker.prepare_duck(self) } end end class Moulder def prepare_duck(duck) puts "heat_plastic" puts "pour_mold" end end class Cooker def prepare_duck(duck) puts "set_oven_temp('150')" puts "cook_for('15min')" end end class Painter def prepare_duck(duck) puts "paint_body('yellow')" puts "paint_beak('orange')" puts "paint_eyes" end end class QualityAssurance def prepare_duck(duck) puts "float_duck" puts "inspect_duck" end end class Packager def prepare_duck(duck) puts "wrap_duck" puts "box_duck" end end d = Duck.new d.prepare([Moulder.new, Cooker.new, Painter.new, QualityAssurance.new, Packager.new])

    改造后,如果后续需要加入运输流程:

    6.Transporter发送小黄鸭。

    只需给Transporter定义一个prepare_duck的方法,而无需改动duck的代码。

    class Transporter def prepare_duck(duck) puts "sending" end end d = Duck.new d.prepare([Moulder.new, Cooker.new, Painter.new, QualityAssurance.new, Packager.new, Transporter.new])

    套用Duck Typing的说法“如果一个流程实现了prepare_duck的方法,那么它就可以并入到duck的制作流程中”。

    这里只关心prepare_duck这个行为,而不关心其具体的类。

    考虑下如果想给制作流程增加限制条件(每个流程都依赖前一流程),要怎么实现?

    class Duck attr_access :processes def prepare(workers) workers.each do |work| if(self.is_prepared(work) work.prepare_duck(self) self.add_process(work.name, true) end end end def add_process(name, value) item = @processes[name]; if(item) item.value = value; else @processes[name] = { name: name, value: value } end end def is_prepared(process) if(process) process.pre ? @proecess[process.pre].value : true else @processes.values.filter{|p| return !p.value}.length end end end class Moulder attr_writer :name attr_writer :pre def name @name || "moduler" end def pre @pre || null end def prepare_duck(duck) ... end end class Cooker attr_writer :name attr_writer :pre def name @name || "cooker" end def pre @pre || "moduler" end def prepare_duck(duck) ... end end ... d = Duck.new d.prepare([Moulder.new, Cooker.new, Painter.new, QualityAssurance.new, Packager.new, Transporter.new]) puts "congratulation your duck is prepared!" if d.is_prepared()