React Hooks — это здорово. Они чистые, легко читаемые и экономят время при наборе стандартного текста. Тем не менее, они очень новые, и многие популярные учебники еще не полностью приняли их, особенно в Redux. В этом посте я возьму компонент из учебника Брэда Трэверси MERN Stack Front To Back и преобразую его для использования хуков Redux.

Ниже находится компонент Posts. Мы будем использовать хуки для доступа к состоянию post и отправки getPosts без connect.

import React, { Fragment, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = ({ getPosts, post: { posts } }) => {
  useEffect(() => {
    getPosts()
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
  post: state.post
})
export default connect(mapStateToProps, { getPosts })(Posts)

Во-первых, мы можем заменить import { connect } from 'react-redux' на import { useSelector, useDispatch } from 'react-redux'.

import React, { Fragment, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useSelector, useDispatch } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = ({ getPosts, post: { posts } }) => {
  useEffect(() => {
    getPosts()
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
  post: state.post
})
export default connect(mapStateToProps, { getPosts })(Posts)

Далее удалите connect(mapStateToprops, {getPosts}) и блок const mapStateToProps.

import React, { Fragment, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useSelector, useDispatch } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = ({ getPosts, post: { posts } }) => {
  useEffect(() => {
    getPosts()
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
}
export default Posts

Теперь мы готовы к крючкам. Во-первых, это крючок useSelector, который получит posts из state.post.

import React, { Fragment, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useSelector, useDispatch } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = ({ getPosts, post: { posts } }) => {
  const { posts } = useSelector(state => state.post)
  useEffect(() => {
    getPosts()
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
}
export default Posts

После этого мы добавим хук useDispatch, который позволит нам запустить нашу функцию getPosts, взяв ее в качестве аргумента, например: dispatch(getPosts()).

import React, { Fragment, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useSelector, useDispatch } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = ({ getPosts, post: { posts } }) => {
  const { posts } = useSelector(state => state.post)
  
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(getPosts())
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
}
export default Posts

Теперь вы можете удалить реквизиты из компонента Posts, а также PropTypes — поскольку нет реквизитов для проверки типов. И вы сделали! Попробуй сам.

import React, { Fragment, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import PostItem from './PostItem'
import PostForm from './PostForm'
import { getPosts } from '../../actions/post'
const Posts = () => {
  const { posts } = useSelector(state => state.post)
  
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(getPosts())
  }, [getPosts])
  return (
    <Fragment>
      <h1 className="large text-primary">Posts</h1>
      <p className="lead">
        <i className="fas fa-user" /> Welcome to the community
      </p>
      <PostForm />
      <div className="posts">
        {posts.map((post) => (
          <PostItem key={post._id} post={post} />
        ))}
      </div>
    </Fragment>
  )
}
export default Posts

Примечание. Если вы используете какие-либо данные не из состояния, вам все равно нужно будет передать их в реквизиты.

Для меня этот код выглядит намного чище. Синтаксис connect и mapStateToProps громоздкий для ввода и неразборчивый для чтения. Спасибо Хукс!

Первоначально опубликовано на https://harryherskowitz.com 23 августа 2020 г.