群组信息 私有

administrators

 

成员列表

  • Create React App build 不起来

    内存问题可以用以下方法来解决:

    "start": "react-app-rewired --max-old-space-size=4096 start",
    "build": "export NODE_OPTIONS='--max-old-space-size=4096' && react-app-rewired build",
    
    发布在 笔记
  • RE: 免费安装网站安全证书

    今天手动更新,碰到这个错误:

    No module named _cffi_backend

    不知何故,不过容易解决,重新装一箱cffi就可以了:

    For python2.x use following command:

    python -m pip install cffi

    for python3.x

    python3 -m pip install cffi

    发布在 笔记
  • React16后的新功能

    软件版本通常分3级:

    • 第一个数字代表大版本
    • 第二个数字代表小版本
    • 第三个数字代表小打小闹 - bug fixes等

    V15 到 V16 是大版本升级,惊心动魄的新功能不少:

    1. fragments - 曾几何时,render()必须且只能返回一个node,因此,你不得不加上一些不必要的<div>把多个node包起来。fragments 让你可以直接render一个数组。这个配上map真是太完美了。注意:key是需要的,这个有点烦。所以v16.2.0后,我们可以用特殊字符<>, 例如:<><li /><li /><>,这样可以就可省略了。

    2. 对了,你可以直接返回字符串了 - 不由再次感叹:曾几何时,render()必须且只能返回一个node

    3. contextAPI - 就是说createContext之后,可以在一个component里提供provider,例外一个component里通过consumer来读取
      祝:这个我基本上没用过 - 因为我要吗直接传props,或者用其他state管理,例如:redux或者mobx等。

    4. createRef API - 这个在不受控制的form还是很有用的。受控制指通过react state来控制form的字。

    5. 新的lifecycles

    • getDerivedStateFromProps
    • getSnashotBeforeUpdate

    注意:几个will的lifecycles, 到V17后就没有life了。所以,大家有空还是看看上面两个新的lifecyles吧。

    1. StrictMode - 用了发现下面几个潜在问题
    • Identifying components with unsafe lifecycles
    • Warning about legacy string ref API usage
    • Detecting unexpected side effects
    1. React.memo - 用来替代PureComponent 或者 shouldComponentUpdate, memo让component变存, 或者说只有props变才重新render。如只是父级component变了,memo子component不会重新render

    2. React.lazy - 用来实现code-split - 基本是react loadable的复制版。

    下面几个还没出:

    1. Hooks - 让functional component 可以使用 state 通过 useState()

    2. suspend

    3. concurrent rendering

    10和11 基本上是用了提供弱CPU和慢网速用户的用户体验。大概意思:hold住render,知道数据ready,这样对网速快的用户少了loading icon,对慢用户仍然有repsond。这个概念有点难,等真正开始用了,我们再深入!

    发布在 React
  • 让footer黏在页面最下方的最佳方案

    这个问题困扰我很久,每次我都要Google找答案,虽然每次都可以搞定,但是回头又忘记当时是怎么做的了。几天又上网搜了搜,就得这个一定是最佳方案了!记下,记下!

    HTML

    <!doctype html>
    <html lang="en">
    
    <head>
      <!-- head content -->
    </head>
    
    <body>
      <header>
        <!-- header content -->
        <h1>Hello header!</h1>
      </header>
      <main>
        <!-- page content -->
        <p>Hello main content!</p>
      </main>
      <footer>
        <!-- footer content -->
        <p>
          I like sitting at the bottom :-)</p>
      </footer>
    </body>
    

    CSS

    body {
      display: flex;
      flex-direction: column;
      min-height: 100vh;
      margin: 0 /** this is super important **/
    }
    footer {
      margin: auto auto 0 auto;
    }
    

    演示

    https://codepen.io/adamcai/pen/YBXKMQ?editors=1100

    发布在 笔记
  • RE: 推荐阅读 发布在 笔记
  • 鼠标选择加亮 发布在 笔记
  • Promise - Part 7 of 函数式编程

    Promise (承诺) 函数用于实现callback的功能,即在一个函数结束后调用另外一个函数。
    比如下面这个例子:

    function do_thing1(){
      setTimeout( function(){
        console.log( 'do thing1' );
      }, 1000 );
    }
     
    function do_thing2(){
      console.log( 'do thing2' );
    }
     
    do_thing1();
    do_thing2();
    

    这里我们先调用do_thing1因为我们希望do_thing2do_thing1结束后再执行,但是do_thing2没有等!

    我们可以用传统的callback来解决这个问题如下:

    function do_thing1(callback){
      setTimeout( function(){
        console.log( 'do thing1' );
        callback && callback()
      }, 1000 );
    }
     
    function do_thing2(){
      console.log( 'do thing2' );
    }
    do_thing1(do_thing2);
    

    我把do_thing2当做一个变量传给do_thing1,等do_thing1结束后来调用do_thing2。

    接下来,我们用Promise来解决这个问题:

    const do_thing1b = new Promise((resolve, reject) =>
      setTimeout(() => {
        console.log("do_thing1b");
        resolve("done");
      }, 1000)
    );
    
    const do_thing2b = () => {
      console.log("do thing2b");
    };
    
    do_thing1b.then(() => do_thing2b());
    

    因为do_thing1b现在是个Promise,所以我们可以用then来串接其他函数,即do_thing2,这样就确保do_thing2b一定在do_thing1b结束后才被调用。这就"承诺"!

    发布在 香草Javascript🌿
  • 微软浪费我不少的时间

    用Mac快4年了,偶尔到PC上除了一点东西,我擦,那个慢啊!不比不知道,我们在Windows上浪费了多少时间!

    发布在 笔记
  • Recursion - Part 6 of 函数式编程

    递归函数指自己调用自己直到被停止。
    说起Recursion - 递归,你如果学过计算机科学, 那么一定会想起斐波那契。(1,1,2,3,5,8,...)

    function feibo(n) {
      if (n === 1) {
        return 1;
      } else if (n < 1) {
        return 0;
      } else {
        return feibo(n - 1) + feibo(n - 2);
      }
    }
    

    其实在我的前端工作中,很少涉及斐波那契这样的算法题。那么需要前端需要递归吗?看看下面这个例子,

    const categories = [
      { id: "animals", parent: null },
      { id: "mammals", parent: "animals" },
      { id: "cats", parent: "mammals" },
      { id: "dogs", parent: "mammals" },
      { id: "aHuang", parent: "dogs" },
      { id: "aMi", parent: "cats" },
      { id: "aTu", parent: "dogs" },
      { id: "aMao", parent: "cats" }
    ];
    
    const makeTree = (categories, parent) => {
      let node = {}; //这个let很重要,它是block scoped的,也就是说下一次进入这个block,新的node被产生
      categories
        .filter(c => c.parent === parent)
        .forEach(item => (node[item.id] = makeTree(categories, item.id)));
      return node;
    };
    
    console.log(JSON.stringify(makeTree(categories, null), null, 2));
    

    结果如下:

    {
      "animals": {
        "mammals": {
          "cats": {
            "aMi": {},
            "aMao": {}
          },
          "dogs": {
            "aHuang": {},
            "aTu": {}
          }
        }
      }
    }
    

    这里我们把一组数据转换成树状结构,按照父系相同归类。这个如果用for loop,代码一定很乱,makeTree这么写还是挺酷的吧?

    总而言之,递归的作用是简化代码 - 这也是函数式编程的中心思想!

    看Pen: https://codepen.io/adamcai/pen/LMEdgR

    发布在 香草Javascript🌿
  • Curry - Part 5 of 函数式编程

    Curry (咖喱)函数 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。如果你不知道我在说什么,没关系,一步一步来:
    首先看一个普通函数:

    function person = (name, height, weight) {
      return name + '身高' + height + ', 体重' + weight;
    }
    

    用ES6箭头函数可以简写为:

    const person = (name, height, weight) =>
      name + '身高' + height + ', 体重' + weight;
    
    console.log(person('Tom', '1米78', '150公斤'));
    //Tom身高1米78, 体重150公斤
    

    如果你不知道为什么可以这么写,请查看[这里]。(https://j4fun.com/topic/48/map-arrow函数的简写-part-2-of-函数式编程)
    接下来,我们把以上函数用咖喱函数来表示:

    function curryPersonFunction (name) {
      return function personHeightWeight(height, weight) {
        return name + '身高' + height + ', 体重' + weight;
      }
    }
    

    注意:curryPersonFunction()函数现在只接一个参数name,然后返回一个函数personHeightWeight()。这么一来,我们可以用下面的函数调用来实现上面普通函数需要实现的结果:

    const tom = curryPersonFunction('Tom'); //tom 在这里是一个函数
    console.log(tom('1米78', '150公斤'));
    //Tom身高1米78, 体重150公斤
    

    以上的例子或许不能解释为什么要用Curry函数,但是发挥点想象力,你可能注意到,我们可以用Curry函数把一部分函数单独分离出来,这样就可以重复使用它来提高代码的可读性。

    比如下面这个例子:

    const data = {
        "user": "adam",
        "posts": [
            { "title": "why curry?", "contents": "curry is cool" },
            { "title": "why functional", "contents": "functional is clean" }
        ]
    };
    
    function getObjProp(propName, obj){
      return obj[propName];
    }
    
    const titles = getObjProp("posts", data).map(post => {
      return getObjProp("title", post)
    });
    
    console.log(titles);
    //["why curry?","why functional"]
    

    上面例子里,getObjProp是一个普通函数,它接受两个参数,一个是属性名,另外一个是object,然后返回这个属性的值。如果把它写成curry函数,在配上“级联”函数,比如map,我们就不用每次都传入object了。

    const get = prop => obj => obj[prop];
    const titles = get('posts')(data).map(get('title'));
    

    本章对于codePen:
    例子一:Curry基础
    例子二:Curry和Map的妙用

    发布在 香草Javascript🌿