react中反复提到的函数式编程到底是什么

203 阅读1分钟

什么是函数式编程

  • 如果给定相同的参数,则返回相同的结果(也称为确定性)。
  • 它不会引起任何副作用

确定性

let PI = 3.14;

const calculateArea = (radius) => radius * radius * PI;

calculateArea(10); // returns 314.0

这是一个计算面积的函数,圆周率是我们熟知的3.14,但如果有一天数学家们发现圆周率不是3.14,而是4.14了,那程序的执行结果会变成这样

let PI = 3.14;

const calculateArea = (radius) => radius * radius * PI;

calculateArea(10); // returns 414.0

可以看到虽然每次都是同样的参数,但是并没有得到同样的输出,这显然不是一个纯函数,我们稍微改造一下

let PI = 3.14;

const calculateArea = (radius, PI) => radius * radius * PI;

这样子函数的输出就不会被外部的变量影响,这就是纯函数的确定性

不会有副作用

下面的函数在执行时会影响到外部变量,这种副作用可能会导致我们的程序出现意料之外的bug

const arr = [2, 4, 6];

function addElement(arr, ele) {
  arr.push(ele);
}

addElement(arr, 8);

console.log("original data", arr); // [2, 4, 6, 8]

我们稍微改一下代码

const arr = [2, 4, 6];

function addElement(arr, ele) {
  return [...arr, ele];
}

console.log("modified data", addElement(arr, 8)); //  [2, 4, 6, 8]
console.log("original data", arr); //  [2, 4, 6]

这样子就不会影响到外部的变量,这就是函数式编程的不会引起副作用

函数式编程在react中的体现

reducer

const initialState = {
    data: [],
    loading: true
};

const reducer = (state = initialState, action: any) => {
  switch (action.type) {
    case "search":
      return {
        ...state,
        data: action.payload,
        loading: false
      };
    default:
      return state;
  }
};

函数组件

const Counter = ({ count }) => {
  return <h3>{`Count: ${count}`}</h3>;
};

setState

import { useState } from "react";
const App = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => setCount(count + 1);

  return (
    // ...
  );
};

const Counter = ({ count }) => {
  // ...
};

export default App;

在setCount中,我们用了一个count变量而不是通过一个参数传递进去,这就有悖于函数式编程的概念,我们可以改一下这行代码

const handleClick = () => setCount((prev) => prev + 1);

可以看到,count的值便取决于传入callback中的参数prev,类比classComponent中的setState

data immutable 数据不可变

import { useState } from "react";

const App = () => {
  const [person, setPerson] = useState({
    fName: "",
    lName: ""
  });

  const handleChange = (e) => {
    setPerson({
      ...person,
      [e.target.name]: e.target.value
    });
  };

  return (
    // ...
  );
};

export default App;

react中我们通过setState去改变状态触发re-render,但是我们要赋予setState的是一个全新的data,而不是去改变原来的data,保证数据不可变,也是遵循函数式编程

避免副作用 useEffect

const Counter = ({ count }) => {
  document.title = `Number of click: ${count}`;
  return <h3>{`Count: ${count}`}</h3>;
};

这个组件中,我们改变了不属于这个组件的dom元素,产生了副作用,让组件变得不够纯粹,我们试着把这段副作用代码放到useEffect中

const Counter = ({ count }) => {
  useEffect(() => {
    document.title = `Number of click: ${count}`;
  }, [count]);

  return <h3>{`Count: ${count}`}</h3>;
};

HOC && renderProps

HOC和renderProps中也体现了函数式编程的思想,想了解的可以👇
你还不懂的React高阶指引?