聊聊 React

apolis發表於2021-01-20

都說 React 開發效率高,但效率高在哪呢?來細看看。

用 d3 寫一個 List:

const renderList = data => {
  d3.select("ul")
    .selectAll("li")
    .data(data, d => d.id)
    .join(
      enter => enter.append("li").text(d => d.text),
      update => update.text(d => d.text),
      exit => exit.remove()
    );
};

d3 把 view 和 data 的關係分為 3 種:

  • enter:有 data 沒 view
  • update:有 data 有 view
  • exit:有 view 沒 data

資料更新,開發者需考慮「新 view」對比「老 view」,新增的「enter」、更新的「update」、減少的「exit」要怎麼處理。


用 React 來寫:

const List = ({ data }) => {
  return (
    <ul>
      {data.map(d => (
        <li key={d.id}>{d.text}</li>
      ))}
    </ul>
  );
};

資料更新,開發者只需考慮「新 view」是什麼樣,不用考慮怎麼把「老 view」變成「新 view」,比 d3 簡單。


React 是不是比 d3 好用?

答:不一定,要看場景。React 框架把「新增的、更新的、減少的處理」都做了,開發者沒法干預。但如果你想做一些動畫,需要精細控制「新增的、更新的、減少的」,React 就不如 d3 好用了。

再看 React 程式碼:

const List = ({ data }) => {
  return (
    <ul>
      {data.map(d => (
        <li key={d.id}>{d.text}</li>
      ))}
    </ul>
  );
};

React 把元件簡化成了一個函式,data -> view。元件就是函式,意味著函式可以怎麼玩,元件就可以怎麼玩。

  • 函式內呼叫別的函式

    function a() {}
    function b() {}
    
    function c() {
      a();
      b();
    }
    
    function A() {}
    function B() {}
    
    function C() {
      return (
        <div>
          <A />
          <B />
        </div>
      );
    }
    
  • 函式的返回值作為別的函式的傳參

    function a() {}
    function b(arg) {}
    
    function c() {
      b(a());
    }
    
    function A() {}
    function B({ children }) {
      return <div>{children}</div>;
    }
    
    function C() {
      return (
        <B>
          <A />
        </B>
      );
    }
    
  • 高階函式

    function memoize(fn) {
      const cache = {};
      return arg => {
        if (cache[arg]) return cache[arg];
        else {
          const result = fn(arg);
          cache[arg] = result;
          return result;
        }
      };
    }
    
    const memoizedSqrt = memoize(Math.sqrt);
    
    const A = () => {};
    const wrapper = Cmp => {};
    const WrappedA = wrapper(A);
    
  • Continuation,或者叫 Callback。Callback 的特點是:等時機成熟後才執行。

    const handler = () => {};
    button.addEventListener("click", handler);
    
    // Context Consumer
    <ThemeContext.Consumer>
      {theme => <Cmp theme={theme} />}
    </ThemeContext.Consumer>
    
    // Render Props
    const MouseTracker = Cmp => {
      return (
        <Mouse
          render={mouse => <Cmp mouse={mouse} />}
        />
      );
    };
    
  • 遞迴

    const factorial = n => {
      if (n === 1) return 1;
      else return n * factorial(n - 1);
    };
    
    const Tree = ({ data }) => (
      <ul>
        {data.map(d => (
          <li key={d.id}>
            {d.text}
            {d.children && <Tree data={d.children} />}
          </li>
        ))}
      </ul>
    );
    

React 元件的種種用法,本質都是函式的用法。從函式的角度來理解、運用 React,就不會覺得這個框架很神祕了。

相關文章