基础知识:
1、安装 Node.js。
2、使用下面的指令创建一个新的项目
npx create-react-app my-app
3、删除掉新项目中 src/ 文件夹下的所有文件。
注意:
不要删除整个 src 文件夹,删除里面的源文件。我们会在接下来的步骤中使用示例代码替换默认源文件。
基础步骤:
第一步:
同函数式组件的搭建方式,如下是搭建完成的页面路径。
第二步:在 src/
文件夹中创建一个名为 index.css
的文件,并拷贝这些 CSS 代码。
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol,
ul {
padding-left: 30px;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
第三步:在 src/
文件夹下创建一个名为 index.js
的文件,并拷贝这些 JS 代码。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square">{ }</button>
);
//return后面的内容加括号,防止VScode等编辑器自动在return后面加分号
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
render() {
const status = 'Next player:X';
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
效果展示:
基础知识:
1、通过阅读代码,我们可以看到有三个 React 组件:
渲染了单独的<button>
渲染了9个方块
渲染了含有默认值的一个棋盘
2、render 方法
3、props 数据传递
数据通过 props 的传递,从父组件流向子组件
基础步骤:
第一步:
修改代码,将数据从 Board 组件传递到 Square 组件
Board
组件的renderSquare方法中,改写代码,将名为value
的 prop 传递到Square
中class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
}
第二步:
class Square extends React.Component {
render() {
return (
<button className="square"> {this.props.value}</button>
);
//return后面的内容加括号,防止VScode等编辑器自动在return后面加分号
}
}
效果展示:
基础代码:
index.css
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol,
ul {
padding-left: 30px;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square"> {this.props.value}</button>
);
//return后面的内容加括号,防止VScode等编辑器自动在return后面加分号
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
render() {
const status = 'Next player:X';
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
基础步骤:
这一步的目标是让棋盘的在点击之后每个格子能落下”X"作为棋子
第一步:
Square 组件中 render()
方法的返回值中的 button 标签
第二步:
增加 onClick 属性
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>{this.props.value}</button>
);
}
}
基础知识:
基础步骤:
第一步:
在 Square 中用构造函数来初始化 state
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button className="square" onClick={() => alert('click')}>{this.props.value}</button>
);
}
}
第二步:
修改 Square 组件的 render 方法,实现每当方格被点击时显示当前 state 值。
在onClick
事件监听函数中调用this.setState
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>
);
}
}
这样子就能实现:在每次<button>
被点击的时候通知React去重新渲染Square
组件
组件更新后,Square
组件的this.state.value
的值会变为'X'
每次在组件中调用setState
,React都会自动更新子组件
效果展示:
点击变成 x
基础代码:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
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 value={i} />;
}
render() {
const status = 'Next player:X';
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
基础步骤:
第一步:
为 Board 组件添加构造函数,将 Board 组件的初始状态设置为长度为 9 的空值数组
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
第二步:
考虑到填充棋盘后,每个格子上可能的形式是null
,O
,X
三种
这些我们打算存储到 squares 数组里面,那么就要修改Board
的renderSquare
方法来读取这些值。
renderSquare(i) {
return <Square value={this.state.squares[i]} />;
}
这样,每个Square
就都能接收到一个 value
prop 了,这个 prop 的值可以是 'X'
、 'O'
、 或 null
(null 代表空方格)。
第三步:
修改 Square 的事件监听函数。
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
第四步:
从 Board 组件向 Square 组件中传递value
和onClick
两个props
参数,修改 Square 组件。
class Square extends React.Component {
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
第五步: 在 Board 下添加handleClick
方法
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({squares: squares});
}
第六步: 实现轮流落子
xIsNext
都会反转,该值确定下一步轮到哪个玩家,并且游戏的状态会被保存下来xIsNext
handleClick
函数constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext? 'X':'O';
this.setState({
squares: squares,
xIsNext:!this.state.xIsNext,
});
}
效果展示:
基础代码:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
const status = 'Next player:X';
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
基础步骤:
第一步:
显示轮到哪个玩家,在 Board 组件的 render 方法中修改 status 的值
const status = 'Next player:'+(this.state.xIsNext?'X':'O');
效果展示:
点击会表面下一个操作的玩家是谁。
基础代码
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
const status = 'Next player:' + (this.state.xIsNext ? 'X' : 'O');
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
基础步骤:
第一步:
定义一个函数:
function calculateWinner(squares) {
const lines = [
[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6],
];
for(let i = 0 ; i < lines.length ; i++) {
const[a,b,c] = lines[i];
if(squares[a]&&squares[a]===squares[b]&&squares[a]===squares[c]){
return squares[a];
}
}
return null;
}
第二步:
在 Board 组件的 render 方法中调用刚刚那个函数检查是否有玩家胜出,有人胜出就把玩家信息显示出来
修改Board
组件的render
方法
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner:' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
效果展示:
O 获得了胜利
基础代码
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 获得胜利的组件
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
class Square extends React.Component {
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner:' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
已经有人胜出了,但是棋盘还能落子 —— 当某个 Square 落子之后,还能覆盖继续落子。
基础步骤:
第一步
修改handleClick
,使得当有玩家胜出时,或者某个 Square 被填充时,该函数不做任何处理直接返回
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext? 'X':'O';
this.setState({
squares: squares,
xIsNext:!this.state.xIsNext,
});
}
效果展示:
基础代码
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 获得胜利的组件
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
class Square extends React.Component {
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (<Square value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner:' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">
{status}
</div>
<div className="board-new">
{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>{ }</div>
<ol>{ }</ol>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
)
阅读量:2010
点赞量:0
收藏量:0