Skip to content

Instantly share code, notes, and snippets.

@Linuxpizi
Last active May 29, 2020 10:44
Show Gist options
  • Save Linuxpizi/4d5b37a0a5824bf8770edb7fe8df1a43 to your computer and use it in GitHub Desktop.
Save Linuxpizi/4d5b37a0a5824bf8770edb7fe8df1a43 to your computer and use it in GitHub Desktop.
使用 Redux 和 React Hooks

原文地址

使用 Redux 和 React Hooks

最新的 React 和 Redux 的更新,增加了新的功能 Hooks。现在我们就可以使用 Hooks替换 React Redux 的 connect 高阶组件。下面我们就来看一下如何使用 Redux Hooks 然后探索 下一些拓展和方法

什么是 Hooks ?

Hooks 在 React 16.8 中添加的新功能,允许你直接访问 state, React 生命周期方法和一 些其它在函数式组件的好处(在类组件中才有的)。


下面的例子,一个类组件

class Count extends React.Component {

    readonly state = {
        count: 0,
    }

    add = () => {
        this.setState({count: this.state.count + 1 });
    }

    render() {
        return (
            <div>
                <p>Count: { this.state.count } </p>
                <button onClick={this.add}>Add</button>
            </div>
        )
    }

}

上面的例子,可以使用 Hooks 写成 函数式组件:

const Count = () => {
    // state variable, initialized to 0
    const [count, setCount] = useState(0)

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Add</button>
        </div>
    )
}

可以看出,下面的代码更加简洁并且允许成员复用组件而不必转换成类组件,当他们想访问 state 或者使用 React 的生命周期方法。这里不会全面的介绍关于 Hooks 的信息。所以,你可以查阅优秀的 Hooks 文档,如果你想学习更多。

如何使用 Redux 的 Hooks ?

React Redux 现在有了自己的 useSelectoruseDispatch Hooks ,他们可以用来替代 connect 高阶组件。

useSelector 类似 connect 的 mapStateToProps。 你传递给它一个函数来获取 Redux store state 并且返回你感兴趣的状态部分

useDispatch 取代 connect 的 mapDispatchToProps 但是它更轻量。 它所作的全部就是返回 store 的 dispath 方法,所以你可以自己派发 actions。我非常喜欢这个改变,因为绑定 action creators 可能会对一些 React Redux 新手比较困惑。

好了,让我们来把一个类组件使用 connect ,转换成使用 Hooks。

使用 connect

import React from "react";
import { connect } from "react-redux";
import { addCount } from "./store/counter/actions";

export const Count = ({ count, addCount }) => {
    return (
        <main>
            <div>Count: {count}</div>
            <button onClick={addCount}>Add to count</button>
        </main>
    )
}

const mapStateToProps = state => ({
  count: state.counter.count
});

const mapDispatchToProps = { addCount };

export default connect(mapStateToProps, mapDispatchToProps)(Count);

好了,我们使用 React Redux Hooks 取代 connect 来实现:

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { addCount } from "./store/counter/actions";

export const Count = () => {
  const count = useSelector(state => state.counter.count);
  const dispatch = useDispatch();

  return (
    <main>
      <div>Count: {count}</div>
      <button onClick={() => dispatch(addCount())}>Add to count</button>
    </main>
  );
};

我很喜欢使用 Redux Hooks 相比于包装的 connect 高阶组件它的概念很少,另一个好处是,相较于高阶组件,它没有被称作"Virtual DOM of death"。

useSelector gotchas(陷阱)

useSelectormapStateToProps 最大的分歧,它使用了严格的对象检查(对象的引用相等)===,来决定组件是否需要重新渲染,例如下面的代码片段

const { count, user } = useSelector(state => ({
    count: state.counter.count,
    user: state.user,
}))

useSelector 每一次调用都会返回一个新的对象。当 store 更新时,React Redux 都会重新运行 useSelector,并且一个新的对象返回,更新组件,这不是我们需要的

一个简单的规则避免使用单一的对象引用 useSelector ,你需要的

const count = useSelector(state => state.counter.count)
const user = useSelector(state => state.user)

或者,当返回一个对象容器包含多个值,显示的告诉 useSelector 使用隐式比较,传递比较方法给第二个参数。

import { shallowEqual, useSelector } from "react-redux";
const { count, user } = useSelector(state => ({
  count: state.counter.count,
  user: state.user,
}), shallowEqual);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment