显示猜测的历史

摘要

  • React 哲学
  • 组件的“参数”
  • JS/TS 中的对象

一个与本节基本一致的 CodeSandbox 中的 demo


现在我们再用 antd 提供的Timeline组件对猜测历史进行渲染。这里同时介绍一下如何定义一个组件,用于将历史渲染的逻辑和游戏的主逻辑尽可能分离。

显然,对于这个小游戏是没必要进行分离的。组件分离层次化一般能起到复用和清晰化的效果。具体使用时如何设计组件并没有定式,推荐阅读React 哲学

src文件夹下新建一个history.tsx,先在其中引入我们需要用到的库并搭一个组件的框架

import React from "react";
import { Timeline } from "antd";

const History: React.FC = () => {
  return <div></div>;
};

export default History;

需要进行渲染的历史需要通过props传入<History />中,因此我们要添加相应的接口

interface HistoryProps {
  history: { value: number; status: string }[];
}

const History: React.FC<HistoryProps> = ({ history }) => {
...
}

这里我们声明了一个HistoryProps作为<History />的接口,其中只有一个history,是由{ value: number; status: string }这样的object构成的“数组”。在定义<History />时使用React.FC<HistoryProps>是定义一个接口为HistoryProps的 React 函数式组件。

接着我们需要将有外层组件传入的history转化为 antd 的<Timeline />的子项形式

<Timeline>
  <Timeline.Item>aaa</Timeline.Item>
  <Timeline.Item>bbb</Timeline.Item>
  <Timeline.Item>ccc</Timeline.Item>
  <Timeline.Item>ddd</Timeline.Item>
</Timeline>

使用maphistory中的每一项都转化为<Timeline.Item>xxx</Timeline.Item>的形式

const historyList = history.map((element) => {
  return (
    <Timeline.Item
      key={element.value}
      color={
        element.status === "You Win"
          ? "green"
          : element.status === "Too small"
          ? "#ffec3d" // 黄色
          : "#ffa940" // 橙色
      }
    >
      You've guessed {element.value}. {element.status}
    </Timeline.Item>
  );
});

这段代码会遍历整个history,将其中的每一项转变为<Timeline.Item color="xxx">You've guessed {element.value}. {element.status}</Timeline.Item>的形式。其中猜测偏小时渲染为黄色,猜测偏大时渲染为橙色,猜对时渲染为绿色。

最后再将historyList作为返回值的一部分

return (
  <div style={{ padding: 10 }}>
    <Timeline>{historyList}</Timeline>
  </div>
);

到这里,<History />就定义完了,我们要在<App />中调用此组件。首先引入该组件,并定义一个存储猜测历史的状态

import History from "./history";

const [history, setHistory] = useState<{ value: number; status: string }[]>(
    []
  );

然后修改handleSubmithandleRandom,加入对历史的修改

const handleSubmit = () => {
  if (guess < secret) {
    message.info("Too small");
    setHistory([...history, { value: guess, status: "Too small" }]);
  } else if (guess > secret) {
    message.info("Too big");
    setHistory([...history, { value: guess, status: "Too big" }]);
  } else {
    message.success("You win");
    setHistory([...history, { value: guess, status: "You Win" }]);
    setRandomAble(true);
  }
};

const handleRandom = () => {
  setSecret(Math.floor(Math.random() * 100 + 1));
  setHistory([]);
  setRandomAble(false);
};

最后在<App />返回的渲染中添加<History />

return (
    ...
    <History history={history} />
);

到此,我们已经实现了游戏的整体功能,渲染效果应与本章最开始的图片一致。


最后的最后,我们再简单看看effect Hook。这是 React 提供的用于执行“副作用”操作的部分,一般用于执行一些网络请求等。

useEffect(() => {
  document.title = `You guess ${guess}`;
}, [guess]);

这一段是在guess改变时,自动修改网页的标题为“You guess ${guess}”