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 г.