将类重构为 React 中的功能组件

Posted

技术标签:

【中文标题】将类重构为 React 中的功能组件【英文标题】:Refactor class to function components in React 【发布时间】:2021-12-28 00:48:30 【问题描述】:

我很难将这 3 个类组件转换为函数组件,类组件正在工作,我只是想将它们转换为学习目的。

API 调用:yelp.js

const  default: SearchBar  = require("../components/SearchBar/SearchBar");

const Yelp = 
    searchYelp(term, location) 
        return fetch(`/api/hello?term=$term&location=$location`)
        .then((response) => 
            // console.log(response)
            return response.json()
        ).then((jsonResponse) => 
            // console.log(jsonResponse)
            if (jsonResponse.businesses) 
                return jsonResponse.businesses.map((business) => 
                    return 
                        id: business.id,
                        imageSrc: business.image_url,
                        name: business.name,
                        address: business.location.address1,
                        city: business.location.city,
                        state: business.location.state,
                        zipCode: business.location.zip_code,
                        category: business.categories.title,
                        rating: business.rating,
                        reviewCount: business.review_count,
                    
                )
            
        )
    


export default Yelp

Home 组件作为渲染 SearchBar 和 BusinessList 组件的函数:Home.js

import React,  useState  from "react";
import BusinessList from '../../../src/components/BusinessList/BusinessList';
import SearchBar from '../../../src/components/SearchBar/SearchBar';
import Yelp from '../../util/yelp';

const Home = (term, location) => 
    const [businesses, setBusinesses] = useState([]);

    const searchYelp = Yelp.searchYelp(term, location).then(businesses => 
        setBusinesses(businesses)
    )

    return (
        <>
            <SearchBar searchYelp=searchYelp />
            <BusinessList business=businesses />
        </>
    )


export default Home;

Home 组件作为一个类:Home.js

// import React from 'react';
// import BusinessList from '../../../src/components/BusinessList/BusinessList';
// import SearchBar from '../../../src/components/SearchBar/SearchBar';
// import Yelp from '../../util/yelp';

// class Home extends React.Component 
//     constructor() 
//         super();
//         this.state = 
//             businesses: [],
//         ;

//         this.searchYelp = this.searchYelp.bind(this);
//     

//     searchYelp(term, location, sortBy) 
//         Yelp.searchYelp(term, location, sortBy).then((businesses) => 
//             this.setState( businesses: businesses )
//         )
//     
//     render() 
//         return (
//             <>
//                 <SearchBar searchYelp=this.searchYelp />
//                 <BusinessList businesses=this.state.businesses />
//             </>
//         )
//     
// 

// export default Home;

BusinessList 组件作为渲染业务组件的函数:BusinessList.js

import React,  useState  from "react";
import './BusinessList.css';
import Business from '../Business/Business';

function BusinessList(businesses) 
    console.log(businesses)
    return (
            <div className="BusinessList">
                
                businesses.map(business => 
                    <Business key=business.id business=business />
                    )
                
            </div>
    )
;

export default BusinessList;

BusinessList 组件作为一个类:BusinessList.js

// import React from 'react';
// import './BusinessList.css';
// import Business from '../Business/Business';

// class BusinessList extends React.Component 
//     constructor(props) 
//         super(props)
//         console.log(props.businesses)
//     

//     render() 
//         return (
//             <div className="BusinessList">
//                 
//                     this.props.businesses.map((business) => 
//                         return <Business key=business.id business=business />
//                     )
//                 
//             </div>
//         )
//     
// ;

// export default BusinessList;

作为函数的业务组件:Business.js

import React from "react";
import './Business.css';

const Business = (business) => 
    return (
        <div className="Business">
            <div className="image-container">
                <img src=business.business.imageSrc alt=business.imageSrc />
            </div>
            <h2>business.business.name</h2>
            <div className="Business-information">
                <div className="Business-address">
                    <p>business.business.address</p>
                    <p>business.business.city&nbsp;business.state&nbsp;business.zipCode</p>
                </div>
                <div className="Business-reviews">
                    <h3>business.business.category</h3>
                    <h3 className="rating">business.business.rating</h3>
                    <p>business.business.reviewCount reviews</p>
                </div>
            </div>
        </div>
    )
;

export default Business;

Business 组件作为一个类:Business.js

// import React from "react";
// import './Business.css';

// class Business extends React.Component 
//     render() 
//         const  business  = this.props

//         return (
//             <div className="Business">
//                 <div className="image-container">
//                     <img src=business.imageSrc alt=business.imageSrc />
//                 </div>
//                 <h2>business.name</h2>
//                 <div className="Business-information">
//                     <div className="Business-address">
//                         <p>business.address</p>
//                         <p>business.city&nbsp;business.state&nbsp;business.zipCode</p>
//                     </div>
//                     <div className="Business-reviews">
//                         <h3>business.category</h3>
//                         <h3 className="rating">business.rating</h3>
//                         <p>business.reviewCount reviews</p>
//                     </div>
//                 </div>
//             </div>
//         )
//     
// ;

// export default Business;

编辑** 我尝试将 SearchBar 组件作为函数:SearchBar.js

import React,  useState, useEffect  from "react";
import './SearchBar.css';

const SearchBar = (props) => 
    const [term, setTerm] = useState('')
    const [location, setLocation] = useState('')
    const [sortBy, setSortBy] = useState('best_match')

    const sortByOptions = 
        'Best Match': 'best_match',
        'Highest Rated': 'rating',
        'Most Reviewed': 'review_count'
    ;

    const handleSortByChange = () => 
        setSortBy(sortBy)
        // console.log(sortByOption)
        console.log(sortBy)
    

    const renderSortByOptions = (sortByOptions) => 
        // console.log(Object.keys(sortByOptions))
        return Object.keys(sortByOptions).map(sortByOption => 
            let sortByOptionValue = sortByOptions[sortByOption]
            // console.log(sortByOptionValue)
            return <li
                className=sortBy === sortByOption ? 'active' : ''
                onClick=handleSortByChange
                key=sortByOptionValue>
                sortByOption
            </li>;
        )
    

    const handleTermChange = (event) => 
        setTerm(event.target.value)
    

    const handleLocationChange = (event) => 
        setLocation(event.target.value)
    

    const handleSearch = (event) => 
        event.preventDefault()
        props.searchYelp(term, location)
    

    return (
        <div className="SearchBar">
            props.searchYelp
            <div className="SearchBar-sort-options">
                <ul>
                    renderSortByOptions(sortByOptions)
                </ul>
            </div>
            <div className="SearchBar-fields">
                <input
                    onChange=handleTermChange
                    placeholder="Search Businesses"
                />
                <input
                    onChange=handleLocationChange
                    placeholder="Where?"
                />
                <button className="SearchBar-submit" onClick=handleSearch>Let's Go</button>
            </div>
        </div>
    )


export default SearchBar;

编辑** SearchBar 组件作为一个类:SearchBar.js

import React from 'react';
import './SearchBar.css';

class SearchBar extends React.Component 
    constructor(props) 
        super(props);
        this.state = 
            term: '',
            location: '',
            sortBy: 'best_match'
        

        this.handleTermChange = this.handleTermChange.bind(this)
        this.handleLocationChange = this.handleLocationChange.bind(this)
        this.handleSearch = this.handleSearch.bind(this)

        this.sortByOptions = 
            'Best Match': 'best_match',
            'Highest Rated': 'rating',
            'Most Reviewed': 'review_count'
        ;
    

    getSortByClass(sortByOption) 
        // console.log(sortByOption)
        if (this.state.sortBy === sortByOption) 
            return 'active'
        
        return ''
    

    handleSortByChange(sortByOption) 
        this.setState(
            sortBy: sortByOption
        )
    

    handleTermChange(event) 
        this.setState(
            term: event.target.value
        )
    

    handleLocationChange(event) 
        this.setState(
            location: event.target.value
        )
    

    handleSearch(event) 
        this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy)
        event.preventDefault()
    

    renderSortByOptions() 
        return Object.keys(this.sortByOptions).map(sortByOption => 
            let sortByOptionValue = this.sortByOptions[sortByOption]
            console.log(sortByOptionValue)
            return <li
                onClick=this.handleSortByChange.bind(this, sortByOptionValue)
                className=this.getSortByClass(sortByOptionValue)
                key=sortByOptionValue>
                sortByOption
            </li>;
        )
    

    render() 
        return (
            <div className="SearchBar">
                this.searchYelp
                <div className="SearchBar-sort-options">
                    <ul>
                        this.renderSortByOptions()
                    </ul>
                </div>
                <div className="SearchBar-fields">
                    <input onChange=this.handleTermChange placeholder="Search Businesses" />
                    <input onChange=this.handleLocationChange placeholder="Where?" />
                    <button className="SearchBar-submit" onClick=this.handleSearch>Let's Go</button>
                </div>
            </div>
        )
    
;

export default SearchBar;

我不断收到错误“无法读取未定义的属性(正在读取“地图”) 或者错误“Businesses.map 不是函数”

我也有点困惑,为什么当我的最终业务组件中的所有内容都转换为功能组件以便显示时,我需要将内容作为 business.business.imageSrc 而不仅仅是 business.imageSrc 传递

p>

【问题讨论】:

【参考方案1】:

首先在Home searchYelp 应该声明为一个函数,以便它可以作为回调传递给SearchBar 组件。

const Home = () => 
  const [businesses, setBusinesses] = useState([]);

  const searchYelp = (term, location) => 
    Yelp.searchYelp(term, location)
      .then(businesses => 
        setBusinesses(businesses);
      );
  ;

  return (
    <>
      <SearchBar searchYelp=searchYelp />
      <BusinessList business=businesses />
    </>
  )
;

然后在BusinessList 中你需要访问传递的business 属性。您当前的代码将 props 对象命名为 businesses,然后尝试对其进行映射。它可能是businesses.business.map,但按照惯例,我们将props 对象命名为props,或者简单地解构你想要使用的props。您还需要返回要映射到的 Business 组件。

function BusinessList( business ) 
  return (
    <div className="BusinessList">
      business.map(business => 
        return <Business key=business.id business=business />;
      )
    </div>
  )
;

Business 组件中的 props 对象名称存在相同问题。

const Business = (props) => 
  return (
    <div className="Business">
      <div className="image-container">
        <img src=props.business.imageSrc alt=props.business.imageSrc />
      </div>
      <h2>props.business.name</h2>
      <div className="Business-information">
        <div className="Business-address">
          <p>props.business.address</p>
          <p>props.business.city&nbsp;props.business.state&nbsp;business.zipCode</p>
        </div>
        <div className="Business-reviews">
          <h3>props.business.category</h3>
          <h3 className="rating">props.business.rating</h3>
          <p>props.business.reviewCount reviews</p>
        </div>
      </div>
    </div>
  )
;

【讨论】:

感谢这个 Drew, 传入 searchYelp 返回未定义,所以我尝试执行 渲染,但是仍然使 searchBar 无法工作......它的控制台记录了搜索结果,但没有将其显示到 DOM。它还在页面加载时返回随机搜索结果而不输入搜索 @Halp_am_stuck 哦,我明白了,您想将回调传递给SearchBar。让我调整一下。请检查更新的答案。 有些东西仍然无法正常工作......在搜索时,我正在返回一个获取的 api 调用,其中未定义传递到 url 中的位置和术语。我认为 SearchBar 组件不会影响这些,但我会更新我的答案以反映 SearchBar 组件代码 @Halp_am_stuck 是的,看看SearchBar 对传递的道具做了什么会很有帮助。 我明白了!我们忘记在 Home.js 中的 searchYelp 函数中传递术语、位置。我想我应该说我你的解决方案已经表明我不知道我是怎么错过的【参考方案2】:

BusinessList 接收props,一个对象包含传入的道具。

函数参数要么需要解构它:

function BusinessList( businesses )  ... 

或从props 对象中引用它:

function BusinessList(props) 
  console.log(props.businesses)
  // ...

【讨论】:

【参考方案3】:

几点说明:

现在Yelp.searchYelp 返回Promise&lt;any[] | undefined&gt;,即undefined 是消费者可以获得的合法值。当businesses 未定义时,由您决定setBusinesses(businesses) 是否有用,但在这种情况下,请处理它。否则默认为空数组,setBusinesses(businesses ?? []) 或抛出错误。 不要在渲染阶段运行副作用,即在 useEffect: 中调用 api:
React.useEffect(() => 
    const searchYelp = Yelp.searchYelp(term, location).then(businesses => 
        setBusinesses(businesses ?? [])
    )
, [term, location])
最后,const Business = (business) =&gt; 这里的business 实际上是 props 对象。您可以简单地对其const Business = ( business ) =&gt; 进行解构以直接获取值。

【讨论】:

?? [] 我不熟悉这种语法......这是否像一个类似于三元运算符的奇怪反应条件? 它只是合并运算符。 (大部分)businesses ? businesses : [] 的语法糖

以上是关于将类重构为 React 中的功能组件的主要内容,如果未能解决你的问题,请参考以下文章

如何将类组件转换为功能组件?

将类组件转换为功能组件

react中从类重构为功能钩子组件

如何将类组件转换为功能组件?

在 React 中将类组件转换为功能组件

如何将类组件重写为 React Functional?