-
Notifications
You must be signed in to change notification settings - Fork 0
Lesson 4 react component JSX #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| import React from 'react'; | ||
| import { render } from 'react-dom'; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| .cell { | ||
| background: #fff; | ||
| border: 1px solid #999; | ||
| font-size: 24px; | ||
| font-weight: bold; | ||
| line-height: 34px; | ||
| height: 34px; | ||
| margin-right: -1px; | ||
| margin-top: -1px; | ||
| padding: 0; | ||
| text-align: center; | ||
| width: 34px; | ||
| display: inline-block; | ||
| } | ||
|
|
||
| .cell-empty { | ||
| border-color: gray; | ||
| } | ||
|
|
||
| .cell-filled { | ||
| border-color: #fff; | ||
| background: black; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import React from 'react'; | ||
| import { Cell } from './Cell'; | ||
| import { withKnobs, number } from '@storybook/addon-knobs'; | ||
|
|
||
| // eslint-disable-next-line no-restricted-syntax | ||
| export default { | ||
| title: 'Lesson 4 / Cell', | ||
| decorators: [withKnobs], | ||
| }; | ||
|
|
||
| export const nonFilled = () => [ | ||
| <Cell x={number('x', 1)} y={number('y', 23)} key="stroies" />, | ||
| ]; | ||
|
|
||
| export const Filled = () => [ | ||
| <Cell filled={true} x={number('x', 1)} y={number('y', 23)} key="stroies" />, | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import React from 'react'; | ||
| import { mount } from 'enzyme'; | ||
| import { Cell } from './Cell'; | ||
|
|
||
| test.each` | ||
| inputFilled | expected | ||
| ${true} | ${'<div class="cell cell-filled"></div>'} | ||
| ${false} | ${'<div class="cell cell-empty"></div>'} | ||
| `('renders cell for empty or filled', ({ inputFilled, expected }) => { | ||
| const cellItem = mount(<Cell filled={inputFilled} x={1} y={2} />); | ||
|
|
||
| expect(cellItem.html()).toBe(expected); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import React, { FC } from 'react'; | ||
| import './Cell.css'; | ||
| import type { CellProps } from './Interfaces'; | ||
|
|
||
| const Cell: FC<CellProps> = ({ filled, x, y }) => { | ||
| if (filled) { | ||
| return <div className="cell cell-filled">{filled}</div>; | ||
| } | ||
|
|
||
| return <div className="cell cell-empty"></div>; | ||
| }; | ||
|
|
||
| export { Cell }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| p { | ||
| margin: 0; | ||
| padding: 0; | ||
| line-height: 0; | ||
| } | ||
| div { | ||
| margin: 0; | ||
| padding: 0; | ||
| line-height: 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import React from 'react'; | ||
| import { Field } from './Field'; | ||
| import { withKnobs, object } from '@storybook/addon-knobs'; | ||
|
|
||
| // eslint-disable-next-line no-restricted-syntax | ||
| export default { | ||
| title: 'Lesson 4 / Field', | ||
| decorators: [withKnobs], | ||
| }; | ||
|
|
||
| const cellGridFillRandom = (cellStatus = () => Math.random() < 0.3) => { | ||
| const grid: boolean[][] = []; | ||
| for (let y = 0; y < 10; y++) { | ||
| grid[y] = []; | ||
| for (let x = 0; x < 10; x++) { | ||
| grid[y][x] = cellStatus(); | ||
| } | ||
| } | ||
| return grid; | ||
| }; | ||
|
|
||
| const cellGridNonFill = () => | ||
| Array.from<boolean[]>({ length: 10 }).fill( | ||
| Array.from<boolean>({ length: 10 }).fill(false), | ||
| ); | ||
|
|
||
| export const emptyCell = () => [ | ||
| <Field field={object('field', cellGridNonFill())} key="stories" />, | ||
| ]; | ||
|
|
||
| export const notEmptyCell = () => [ | ||
| <Field field={object('field', cellGridFillRandom())} key="stories" />, | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import React from 'react'; | ||
| import { mount } from 'enzyme'; | ||
| import { Field } from './Field'; | ||
|
|
||
| test.each` | ||
| inputFilled | expectedBr | expectedDiv | expectedCellEmpty | expectedCellFilled | ||
| ${[ | ||
| [true, false, true, true, false, true, true, true, false, true], | ||
| [true, true, true, true, false, false, false, true, false, true], | ||
| ]} | ${2} | ${20} | ${7} | ${13} | ||
| `( | ||
| 'testing rendering field', | ||
| ({ | ||
| inputFilled, | ||
| expectedBr, | ||
| expectedDiv, | ||
| expectedCellEmpty, | ||
| expectedCellFilled, | ||
| }) => { | ||
| const field = mount(<Field field={inputFilled} />); | ||
| expect(field.find('p').length).toBe(expectedBr); | ||
| expect(field.find('.cell').length).toBe(expectedDiv); | ||
| expect(field.find('.cell-empty').length).toBe(expectedCellEmpty); | ||
| expect(field.find('.cell-filled').length).toBe(expectedCellFilled); | ||
| }, | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import React, { FC } from 'react'; | ||
| import { Cell } from './Cell'; | ||
| import './Field.css'; | ||
| import type { FieldProps } from './Interfaces'; | ||
|
|
||
| const Field: FC<FieldProps> = ({ field }) => ( | ||
| <div className="field"> | ||
| {field.map((row, y) => [ | ||
| ...row.map((filled: boolean, x) => ( | ||
| <Cell key={`${x}_${y}`} filled={field[y][x]} x={x} y={y} /> | ||
| )), | ||
| y !== row.length - 1 ? <p key={y} /> : null, | ||
| ])} | ||
| </div> | ||
| ); | ||
|
|
||
| export { Field }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| .btn { | ||
| margin: 20px 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import React from 'react'; | ||
| import { withKnobs, number } from '@storybook/addon-knobs'; | ||
| import { Field } from './Field'; | ||
| import { GameOfLifeProto } from './GameOfLifeProto'; | ||
|
|
||
| // eslint-disable-next-line no-restricted-syntax | ||
| export default { | ||
| title: 'Lesson 4 / GameOfLifeProto', | ||
| decorators: [withKnobs], | ||
| }; | ||
|
|
||
| export const GameOfLifePrototip = () => ( | ||
| <GameOfLifeProto | ||
| columns={number('columns', 20)} | ||
| rows={number('rows', 20)} | ||
| fieldComponent={Field} | ||
| /> | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import { mount, shallow } from 'enzyme'; | ||
| import GameOfLifeProto from './GameOfLifeProto'; | ||
|
|
||
| describe('GameOfLifeComponent testing', () => {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import React from 'react'; | ||
| import './GameOfLifeProto.css'; | ||
|
|
||
| type FieldPropsComponent = React.FC<{ | ||
| field: boolean[][]; | ||
| }>; | ||
|
|
||
| interface FieldPropsInterface { | ||
| rows: number; | ||
| columns: number; | ||
| fieldComponent: FieldPropsComponent; | ||
| } | ||
|
|
||
| interface FieldState { | ||
| fieldState: boolean[][]; | ||
| } | ||
|
|
||
| const cellGridFillRandom = ( | ||
| rows: number, | ||
| columns: number, | ||
| cellStatus = () => Math.random() < 0.3, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а зачем ты эту функцию несколько раз инлайново определяешь?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вроде один раз же определил в этом компоненте? Или я недопонял вопроса( |
||
| ) => { | ||
| const grid: boolean[][] = []; | ||
| for (let y = 0; y < rows; y++) { | ||
| grid[y] = []; | ||
| for (let x = 0; x < columns; x++) { | ||
| grid[y][x] = cellStatus(); | ||
| } | ||
| } | ||
| return grid; | ||
| }; | ||
|
|
||
| class GameOfLifeProto extends React.Component<FieldPropsInterface, FieldState> { | ||
| private fieldComponent: FieldPropsComponent; | ||
|
|
||
| constructor(props: FieldPropsInterface) { | ||
| super(props); | ||
| this.fieldComponent = props.fieldComponent; | ||
| this.state = { | ||
| fieldState: cellGridFillRandom(this.props.rows, this.props.columns), | ||
| }; | ||
| } | ||
|
|
||
| public onClick() { | ||
| this.setState(() => { | ||
| const cloneFieldState = cellGridFillRandom( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. на сколько я вижу, здесь коллбэк не обязателен |
||
| this.props.rows, | ||
| this.props.columns, | ||
| ); | ||
|
|
||
| return { | ||
| fieldState: cloneFieldState, | ||
| }; | ||
| }); | ||
| } | ||
|
|
||
| render() { | ||
| const FieldComponent = this.fieldComponent; | ||
| return ( | ||
| <> | ||
| <FieldComponent field={this.state.fieldState} /> | ||
| <button className="btn" onClick={() => this.onClick()}> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ты в конструкторе завязал контекст у метода - для чего? я к тому, что тут можно обойтись без стрелочной функции
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Я заготовку начал делать видимо для метода, который будет при клике возвращать координаты ячейки и видимо забыл убрать, я уберу эту привязку |
||
| {'Обновить'} | ||
| </button> | ||
| </> | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export { GameOfLifeProto }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| export interface CellProps { | ||
| filled?: boolean; | ||
| x?: number; | ||
| y?: number; | ||
| } | ||
|
|
||
| export interface FieldProps { | ||
| field: boolean[][]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
что это?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Этого не должно быть здесь, перекину в векту master, предпологалось как шаблон использовать