Hôm nay, chúng ta sẽ cùng nhau xây dựng game cờ caro dựa trên những kiến thức đã học ở bài trước nha. Các bạn có thể check kết quả tại đây: Final Result. Bạn hãy thử chơi game để biết chúng ta sẽ xây dựng game như thế nào.
Để có thể hiểu được bài này, các bạn nên xem qua các bài trước của mình và đã setup môi trường như bài 1 này: Bài 1: ReactJs - Environment Setup. Nếu như mọi thứ đã ok hết rồi thì ta bắt đầu nào.
Starter Code:
Trong file index.css ta thêm các style sau: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; }
CSS khá dễ hiểu các bạn tự xem nha.
Trong file index.js:
class Square extends React.Component { render() { return ( <button className="square"> {/* TODO */} </button> ); } } 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-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>{/* TODO */}</ol> </div> </div> ); } } // ======================================== ReactDOM.render( <Game />, document.getElementById('root') );
Ở đây, ta tạo 3 component đó là Square, Board và Game.
Square Component sẽ render ra button hình ô vuông, mỗi ô vuông có thể xem như 1 nước đi, Board là bảng sẽ render ra 9 Square, Game là component cha chứa Board. Sau khi chạy chương trình npm start các bạn sẽ có kết quả sau: Result.
Passing Data Through Props
Nếu các bạn chưa biết về Props xem qua bài này: Bài 5: ReactJS - Props Overview. Bây giờ ta truyền data từ Board xuống cho Square. Trong renderSquare ta thay đổi như sau:
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
Sau đó thay đổi hàm render trong Square:
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value}
</button>
);
}
}
Kết quả ta được:
An Interactive Component
Bây giờ chúng ta sẽ làm cho giá trị của Square thay đổi thành X mỗi khi ta click vào ô vuông. Đầu tiên ta thử đoạn code sau:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
Nếu bạn click vào ô vuông và xuất hiện alert thì ok.
Bây giờ chúng ta sẽ tạo state cho thằng Square để chứa giá trị và thay đổi mỗi khi ta click phải.
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>
);
}
}
Trong JavaScript classes, chúng ta cần gọi hàm super(); khi chúng ta tạo constructor cho subclass.
Bây giờ ta thay đổi hàm render của Square để hiển thị value là state hiện tại và thay đổi nó mỗi khi có click.
- Thay
this.props.value
bằngthis.state.value
trong<button>
tag. - Thay
() => alert()
event bằng() => this.setState({value: 'X'})
.
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>
);
}
}
Nếu bạn click vào bất kì hình vuông nào, nó sẽ xuất hiện dấu X.
Developer Tools
Nếu các bạn đã xem Bài 13: ReactJS - Tìm hiểu React Extension, công cụ không thể thiếu cho React Developer thì đây là lúc thích hợp để bạn sử dụng Tool này, giờ các bạn có thể inspect các component , xem các props và state mà component đó nắm giữ để hiểu hơn về React Component.
Lifting State Up
Chúng ta đã cơ bản tạo được giao diện game rồi đấy. Nhưng hiện tại mỗi thằng Square giữ một state riêng, để hoàn thiện game chúng ta cần kiểm tra nếu một player win game và ta cần thay đổi nước đi xen kẽ X, O. Để làm được như vậy chúng ta cần chứa 9 states của Square đó ở một component thay vì mỗi component như trước. Và Board component sẽ đảm nhận trọng trách này, chúng ta sẽ tạo một mảng states gồm 9 phần tử tượng trưng cho 9 states của Square, sau đó pass nó xuống Square thông qua props. Ta thay đổi thằng Board như sau:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
renderSquare(i) {
return <Square value={this.state.squares[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>
);
}
}
Bây giờ ta cần xử lý khi 1 Square được click, việc click sẽ thay đổi state trong Board , bởi vì chúng ta không thể update state của Board một cách trực tiếp từ Square nên ta sẽ pass 1 function từ Board xuống Square để thực hiện điều này. Ta thay đổi renderSquare như sau:
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
Board pass 2 props xuống Square: value and onClick. Và giờ chúng ta sẽ xử lý chúng trong Square.
Ta thay đổi như sau:
- Thay this.state.value bằng this.props.value trong Square’s render.
- Thay this.setState() bằng this.props.onClick() trong Square’s render.
- Xóa constructor() vì ta không dùng state nữa.
Sau khi thay đổi đoạn code sẽ như sau:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => this.props.onClick()}>
{this.props.value}
</button>
);
}
}
Bây giờ khi Square được click, nó sẽ gọi onClick function được truyền xuống từ Board. Đây là quá trình code thực hiện, các bạn chịu khó đọc english để hiểu rõ quá trình thực hiện:
- The onClick prop on the built-in DOM <button> component tells React to set up a click event listener.
- When the button is clicked, React will call the onClick event handler defined in Square’s render() method.
- This event handler calls this.props.onClick(). Square’s props were specified by the Board.
- Board passed onClick={() => this.handleClick(i)} to Square, so, when called, it runs this.handleClick(i) on the Board.
- We have not defined the handleClick() method on the Board yet, so the code crashes.
Giờ ta cần tạo function handleClick trong Board component:
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] = 'X';
this.setState({squares: squares});
}
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-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>
);
}
}
Chúng ta gọi hàm .slice() để copy
squares
ra 1 biến tạm sau đó thay đổi biến tạm đó rồi gán ngược lại state khi thay đổi xong. Chúng ta sẽ tìm hiểu việc này ở bài kế.
Bây giờ bạn có thể test lại game trên màn hình, cách chơi vẫn như cũ nhưng giờ đây state không còn được lưu ở Squares nữa mà thay vào đó là Board. Việc này giúp ta có thể xây dựng game tiếp, các bạn để ý là mỗi lần ta update Board's State React sẽ auto chạy lại hàm render giúp ta cập nhật các Squares. Các bạn có thể dùng React Extension để inspect các component để hiểu rõ những gì ta làm nãy giờ:
Viết game caro bằng React |
Trên đây là Top 9 phòng khám da liễu uy tín và chất lượng nhất TP.HCM. Hy vọng, bài viết sẽ giúp bạn có thêm những thông tin hữu ích để có thể lựa chọn cho mình một phòng khám da liễu phù hợp với nhu cầu của bản thân. Nếu bạn có bất kỳ thắc mắc gì cần giải đáp, hãy liên hệ ngay với chúng tôi để được tư vấn và hỗ trợ kịp thời nhé!
Trả lờiXóaChúc bạn ngày càng biết yêu thương, trân trọng bản thân để luôn xinh đẹp và tự tin trong cuộc sống!
Nguồn: https://bom.so/MVUZ29
Nguồn: https://thammyvienula.vn/phong-kham-da-lieu-uy-tin-tp-hcm/
Nguồn: https://thammyvienula.vn/
TOP #9 Phòng khám da liễu uy tín nhất TPHCM – Bạn đã biết?