井字棋小游戏
官网有详细的初始环境配置过程,可以对比这篇教材详解进行学习:官网入门教程跳转链接
一个 package 管理器,比如 Yarn 或 npm。
它能让你充分利用庞大的第三方 package 的生态系统,并且轻松地安装或更新它们。
一个打包器,比如 webpack 或 Parcel。
它能让你编写模块化代码,并将它们组合在一起成为小的 package,以优化加载时间。
一个编译器,例如 Babel。
它能让你编写的新版本 JavaScript 代码,在旧版浏览器中依然能够工作。
初级
1、开启环境
npx create-react-app my-app
cd my-app
npm start
删除src里面的内容,保留文件夹
cd my-app #找到文件位置
cd src # 如果你使用 Windows:
del * #删除掉
cd .. #返回项目文件
在 src/ 文件夹中创建一个名为 index.css 的文件,并拷贝这些CSS 代码 。
在 src/ 文件夹下创建一个名为 index.js 的文件,并拷贝这些 JS 代码。
拷贝以下三行代码到 src/ 文件夹下的 index.js 文件的顶部:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
现在,在项目文件夹下执行 npm start 命令,然后在浏览器访问 http://localhost:3000 。
这样你就可以在浏览器中看见一个空的井字棋的棋盘了。
注意,这里只要更改了js或者css,代码会自动重新运行渲染。
2、解释代码运行原理
状态提升的思想
每个 Square 组件都维护了游戏的状态。我们可以把所有 9 个 Square 的值收集起来,用来判断游戏的优胜者。
如果在棋盘 Board 组件中一个个收集每个格子 Square 组件中的 state。虽然技术上来讲可以实现,但是代码如此编写会让人很难理解,并且我们以后想要维护重构时也会非常困难。因为state分布在各个square里面,就会嵌套得很复杂。
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null, };
}
render() {
return (
<button
className="square"
onClick={
() => this.setState({
value: 'X'})}
>
{
this.state.value}
</button>
);
}
}
class Board extends React.Component {
//这个是父组件
renderSquare(i) {
return <Square />; } //就是为了能够把位置信息i给传递给下一个组件
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{
status}</div>
<div className="board-row">
{
this.renderSquare(0)} {
this.renderSquare(1)} {
this.renderSquare(2)}
</div>
<div className="board-row">
{
this.renderSquare(3)} {
this.renderSquare(4)} {
this.renderSquare(5)}
</div>
<div className="board-row">
{
this.renderSquare(6)} {
this.renderSquare(7)} {
this.renderSquare(8)}
</div>
</div>
);
}
}
class Game extends React.Component {
//爷组件,并没有变化
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{
/* status */}</div>
<ol>{