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

时间:2020-06-10 08:07:30

标签: reactjs

根据this个问题的反馈。我正在尝试将此WrappedApp类组件转换为功能组件。

这是现有的(有效的)类组件:

class WrappedApp extends Component {
      constructor(props) {
        super(props);
        this.state = {
          filterText: "",
          favourites: [],
        };
      }

      // update filterText in state when user types
      filterUpdate(value) {
        this.setState({
          filterText: value,
        });
      }

      // add clicked name ID to the favourites array
      addFavourite(id) {
        const newSet = this.state.favourites.concat([id]);
        this.setState({
          favourites: newSet,
        });
      }

      // remove ID from the favourites array
      deleteFavourite(id) {
        const { favourites } = this.state;
        const newList = [...favourites.slice(0, id), ...favourites.slice(id + 1)];
        this.setState({
          favourites: newList,
        });
      }

      render() {
        const hasSearch = this.state.filterText.length > 0;
        return (
          <div>
            <header>
              <Greeting />
              <Search
                filterVal={this.state.filterText}
                filterUpdate={this.filterUpdate.bind(this)}
              />
            </header>
            <main>
              <ShortList
                data={this.props.data}
                favourites={this.state.favourites}
                deleteFavourite={this.deleteFavourite.bind(this)}
              />

              <TagsList
                data={this.props.data}
                filter={this.state.filterText}
                favourites={this.state.favourites}
                addFavourite={this.addFavourite.bind(this)}
              />
              {/* 
                Show only if user has typed in search.
                To reset the input field, we pass an 
                empty value to the filterUpdate method
              */}
              {hasSearch && (
                <button onClick={this.filterUpdate.bind(this, "")}>
                  Clear Search
                </button>
              )}
            </main>
          </div>
        );
      }
    }

    export default WrappedApp;

此代码在WrappedApp组件和新功能组件中使用/引用:

const Tag = ({ id, info, handleFavourite }) => (
  <li className={info.count} onClick={() => handleFavourite(id)}>
    {info.label} ({info.tag_related_counts_aggregate.aggregate.count})
  </li>
);
const ShortList = ({ favourites, data, deleteFavourite }) => {
  const hasFavourites = favourites.length > 0;
  const favList = favourites.map((fav, i) => {
    return (
      <Tag
        id={i}
        key={i}
        info={data.find((tag) => tag.id === fav)}
        handleFavourite={(id) => deleteFavourite(id)}
      />
    );
  });
  return (
    <div className="favourites">
      <h4>
        {hasFavourites
          ? "Shortlist. Click to remove.."
          : "Click on a tag to shortlist it.."}
      </h4>
      <ul>{favList}</ul>
      {hasFavourites && <hr />}
    </div>
  );
};


const TagsList = ({ data, filter, favourites, addFavourite }) => {
  const input = filter;

  // Gather list of tags
  const tags = data
    // filtering out the tags that...
    .filter((tag, i) => {
      return (
        // ...are already favourited
        favourites.indexOf(tag.id) === -1 &&
        // ...are not matching the current search value
        !tag.label.indexOf(input)
      );
    })
    // ...output a <Name /> component for each name
    .map((tag, i) => {
      // only display tags that match current input string
      return (
        <Tag
          id={tag.id}
          key={i}
          info={tag}
          handleFavourite={(id) => addFavourite(id)}
        />
      );
    });

  /* ##### the component's output ##### */
  return <ul>{tags}</ul>;
};


// need a component class here
// since we are using `refs`
class Search extends Component {
  render() {
    const { filterVal, filterUpdate } = this.props;
    return (
      <form>
        <input
          type="text"
          ref="filterInput"
          placeholder="Type to filter.."
          // binding the input value to state
          value={filterVal}
          onChange={() => {
            filterUpdate(this.refs.filterInput.value);
          }}
        />
      </form>
    );
  }
}

这是我最初尝试将WrappedApp类组件转换为功能组件:

function WrappedApp(props) {
  const [filterText, setfilterText] = useState("");
  const [favourites, setFavourites] = useState([]);

  // update filterText in state when user types
  const filterUpdate = (value) => {
    setfilterText(value);
  };

  // add clicked name ID to the favourites array
  const addFavourite = (id) => {
    const newSet = favourites.concat([id]);
    setFavourites(favourites);
  };

  // remove ID from the favourites array
  const deleteFavourite = (id) => {
    const newList = [...favourites.slice(0, id), ...favourites.slice(id + 1)];
    setFavourites(newList);
  };

  const hasSearch = filterText.length > 0;
  return (
    <div>
      <header>
        <Greeting />
        <Search filterVal filterUpdate />
      </header>
      <main>
        <ShortList data={props.data} favourites deleteFavourite />

        <TagsList
          data={props.data}
          filter={filterText}
          favourites
          addFavourite
        />
        {/* 
            Show only if user has typed in search.
            To reset the input field, we pass an 
            empty value to the filterUpdate method
          */}
        {hasSearch && <button onClick={filterUpdate}>Clear Search</button>}
      </main>
    </div>
  );
}

export default WrappedApp;

我看到什么错误?

我遇到的最初问题是TypeError: favourites.map is not a function错误消息。

2 个答案:

答案 0 :(得分:3)

在评论中出现错误之后,

代替此:

<ShortList data={props.data} favourites deleteFavourite />

使用此:

<ShortList data={props.data} 
  favourites={favourities} 
  deleteFavourite={deleteFavourite} />

仅应用favourites意味着它等于true,而不是处于您所处状态的数组。

答案 1 :(得分:1)

传递道具时,您需要明确指定道具。子组件

<ShortList data={props.data} favourites={favourites} deleteFavourite={deleteFavourite} /> 类似于标签列表

        <TagsList
          data={props.data}
          filter={filterText}
          favourites={favourites}
          addFavourite={addFavourite}
        />