{"id":21836971,"url":"https://github.com/waldohidalgo/all_solution_challenges_legacy_and_current_react_tutorial","last_synced_at":"2025-03-21T14:42:10.099Z","repository":{"id":228421895,"uuid":"773955494","full_name":"waldohidalgo/all_solution_challenges_legacy_and_current_react_tutorial","owner":"waldohidalgo","description":"Soluciones a todos los ejercicios desafíos dejados al final de los tutoriales de React versión Legacy y Current","archived":false,"fork":false,"pushed_at":"2024-03-18T17:41:19.000Z","size":199,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T10:11:53.927Z","etag":null,"topics":["reactjs","reacttutorial","tic-tac-toe","tictactoe"],"latest_commit_sha":null,"homepage":"https://all-solution-challenges-legacy-and-current-react-tutorial.vercel.app/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/waldohidalgo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-18T17:32:01.000Z","updated_at":"2024-03-18T17:38:03.000Z","dependencies_parsed_at":"2024-03-18T19:14:30.640Z","dependency_job_id":null,"html_url":"https://github.com/waldohidalgo/all_solution_challenges_legacy_and_current_react_tutorial","commit_stats":null,"previous_names":["waldohidalgo/all_solution_challenges_legacy_and_current_react_tutorial"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/waldohidalgo","download_url":"https://codeload.github.com/waldohidalgo/all_solution_challenges_legacy_and_current_react_tutorial/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244815968,"owners_count":20515023,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["reactjs","reacttutorial","tic-tac-toe","tictactoe"],"created_at":"2024-11-27T20:43:50.014Z","updated_at":"2025-03-21T14:42:10.071Z","avatar_url":"https://github.com/waldohidalgo.png","language":"JavaScript","readme":"# Soluciones desafíos React Tutorial Legacy y Current Version\n\nEste repositorio contiene el código con el cual resuelvo los desafíos adicionales dejados en el [Tutorial React versión Legacy](https://legacy.reactjs.org/tutorial/tutorial.html#wrapping-up) y [Tutorial React versión Current](https://react.dev/learn/tutorial-tic-tac-toe#wrapping-up) en los cuales se desarrolla el juego Tic Tac Toe. He realizado los desafíos semejantes en ambos tutoriales y además he realizado el primer desafío distinto y único que esta presente en el tutorial actual de React.\n\nLos desafíos del tutorial versión **legacy** de React son los siguientes:\n\n![Desafío React Legacy](./screenshots/react_legacy_tutorial_challenge.webp)\n\nLos desafíos del tutorial versión **current** de React son los siguientes:\n\n![Desafío React Current](./screenshots/react_actual_tutorial_challenge.webp)\n\nA continuación explico el código y muestro screenshots de lo implementado:\n\n## Legacy React Tutorial: 1.Display the location for each move in the format (col, row) in the move history list\n\nPara resolver esto he creado las dos funciones siguientes:\n\n```js\nfunction position(i) {\n  const coord = [\n    [1, 1],\n    [1, 2],\n    [1, 3],\n    [2, 1],\n    [2, 2],\n    [2, 3],\n    [3, 1],\n    [3, 2],\n    [3, 3],\n  ];\n  return coord[i];\n}\n\nexport function indexElementDifferent(squarePrev, squareCurrent) {\n  const indice = squareCurrent.findIndex(\n    (elem, index) =\u003e elem !== squarePrev[index]\n  );\n  return position(indice);\n}\n```\n\nLuego en el componente llamo a la función **indexElementDifferent** con el square del movimiento anterior y el square del movimiento actual:\n\n```JSX\n\u003cbutton\n  className={`${styles[\"button-list_time\"]}\n            ${\n              this.state.indexSeleccionado == move\n                ? styles[\"button-list-selected\"]\n                : undefined\n            }`}\n  onClick={() =\u003e this.jumpTo(move)}\n\u003e\n  {desc}\n  {move\n    ? \"- Position: \" +\n      indexElementDifferent(history[move - 1].squares, step.squares).join(\",\")\n    : \"\"}\n\u003c/button\u003e\n```\n\nCon el código anterior muestro la posición en base a row y column donde se ha hecho la jugada. Solo se muestra para movimientos distintos del primero.\n\n![Posición de jugada en el tablero](./screenshots/winner_o.webp)\n\n## Legacy React Tutorial: 2.Bold the currently selected item in the move list\n\nPara realizar este ejercicio he creado un nueva propieda de estado llamada **indexSeleccionado** la cual inicialmente esta con valor null.\n\n```js\nthis.state = {\n  history: [\n    {\n      squares: Array(9).fill(null),\n    },\n  ],\n  xIsNext: true,\n  indexStep: 0,\n  indexSeleccionado: null,\n  toggleListPosition: true,\n};\n```\n\nCuando se ejecuta el método **jumpTo** al hacer click sobre algún elemento en la lista de movimientos, seteo dicha propiedad de estado **indexSeleccionado** al valor igual al índice de jugada realizada:\n\n```js\njumpTo(step) {\n    this.setState({\n      indexSeleccionado: step,\n      indexStep: step,\n      xIsNext: step % 2 === 0,\n    });\n  }\n```\n\nLuego en los elementos de la lista aplico una clase de estilos para el elemento de la lista con índice igual al valor establecido en el valor de la propiedad de estado **indexSeleccionado**:\n\n```js\nconst stylesButton =\n  this.state.indexSeleccionado == move\n    ? styles[\"button-list-selected\"]\n    : undefined;\n```\n\nA continuación muestro los estilos aplicados al elemento seleccionado en la lista:\n\n![Estilos aplicados elemento lista seleccionado](./screenshots/styles_selected_list_item.png)\n\n## Legacy React Tutorial: 3.Rewrite Board to use two loops to make the squares instead of hardcoding them\n\nInicialmente se tiene el tablero creado de la siguiente manera:\n\n```jsx\n\u003cdiv className=\"board-row\"\u003e\n          {this.renderSquare(0)}\n          {this.renderSquare(1)}\n          {this.renderSquare(2)}\n        \u003c/div\u003e\n        \u003cdiv className=\"board-row\"\u003e\n          {this.renderSquare(3)}\n          {this.renderSquare(4)}\n          {this.renderSquare(5)}\n        \u003c/div\u003e\n        \u003cdiv className=\"board-row\"\u003e\n          {this.renderSquare(6)}\n          {this.renderSquare(7)}\n          {this.renderSquare(8)}\n        \u003c/div\u003e\n```\n\nHe creado dos loops utilizando el método **map** que generan dicho tablero:\n\n```jsx\n[0, 1, 2].map((i) =\u003e (\n  \u003cdiv key={i} className={styles[\"board-row\"]}\u003e\n    {[0, 1, 2].map((j) =\u003e this.renderSquare(j + 3 * i))}\n  \u003c/div\u003e\n));\n```\n\n## Legacy React Tutorial: 4.Add a toggle button that lets you sort the moves in either ascending or descending order\n\nPara resolver este ejercicio he creado una nueva propiedad de estado llamada **toggleListPosition** con valor inicial igual a **true**:\n\n```js\nthis.state = {\n  history: [\n    {\n      squares: Array(9).fill(null),\n    },\n  ],\n  xIsNext: true,\n  indexStep: 0,\n  indexSeleccionado: null,\n  toggleListPosition: true,\n};\n```\n\nLuego creo el método **handleToggleList** que se ejecuta cuando se hace click en el botón creado para cambiar de orden la lista. Dicho método alterna de valor booleano el valor de la propiedad de estado **toggleListPosition**:\n\n```js\nhandleToggleList() {\n    this.setState({\n      toggleListPosition: !this.state.toggleListPosition,\n    });\n  }\n```\n\n```jsx\n\u003cbutton\n  className={styles[\"button-toggle\"]}\n  onClick={() =\u003e this.handleToggleList()}\n\u003e\n  Toggle List Order\n\u003c/button\u003e\n```\n\nPor último, procedo a cambiar de orden los números de la lista en el atributo **reversed** en función del valor booleano de la propiedad de estado **toggleListPosition**:\n\n```jsx\n\u003col\n  reversed={!this.state.toggleListPosition}\n  className={styles[\"container-time-list\"]}\n\u003e\n  {this.state.toggleListPosition ? moves : moves.reverse()}\n\u003c/ol\u003e\n```\n\nEl resultado de hacer click en el botón para realizar cambio de orden de la lista de movimientos es el siguiente:\n\n![Toggle List Items](/screenshots/toggle_list.webp)\n\n## Legacy React Tutorial: 5.When someone wins, highlight the three squares that caused the win\n\nHe creado la función **squaresPositionWinner** la cual recibe como parámetro el array con los strings en el tablero que representan la jugada hecha cuando existe un ganador y retorna los índices que corresponden al string que gano el juego ya sea 'X' ó 'O':\n\n```js\nconst lines = [\n  [0, 1, 2],\n  [3, 4, 5],\n  [6, 7, 8],\n  [0, 3, 6],\n  [1, 4, 7],\n  [2, 5, 8],\n  [0, 4, 8],\n  [2, 4, 6],\n];\nexport function squaresPositionWinner(squares) {\n  for (let i = 0; i \u003c lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] \u0026\u0026 squares[a] === squares[b] \u0026\u0026 squares[a] === squares[c]) {\n      return [a, b, c];\n    }\n  }\n}\n```\n\nComo el array de squares que representan cada jugada se encuentra en el componente root o padre llamado **Game** procedo a enviar como props dicho squares que representa la jugada cuando existe ganador de modo que dicho array llegue al componente **Square**. Además, hago envío a dicho componente el índice que representa a cada **Square**. Cuando existe un ganador, comparo el índice del Square con el índice de la posición ganadora y si son iguales pongo un color de fondo igual a #FFDF00 y en caso contrario pongo un color de fondo igual a blanco:\n\n```jsx\nfunction Square(props) {\n  return (\n    \u003cbutton\n      style={\n        props.winner \u0026\u0026\n        squaresPositionWinner(props.winner).includes(props.position)\n          ? { backgroundColor: \"#FFDF00\" }\n          : { backgroundColor: \"white\" }\n      }\n      className={styles.square}\n      onClick={props.onClick}\n    \u003e\n      {props.value}\n    \u003c/button\u003e\n  );\n}\n```\n\nA continuación muestro la imagen con ganador igual a X:\n\n![Destaque de color cuando existe ganador X](./screenshots/winner_x.webp)\n\nA continuación muestro la imagen con ganador igual a :\n\n![Destaque de color cuando existe ganador O](./screenshots/winner_o.webp)\n\n## Legacy React Tutorial: 6.When no one wins, display a message about the result being a draw\n\nCuando no existe ganador y no se pueden realizar más movimientos, entonces aquello implica que **TODAS** las posiciones del array **squares** poseen algún elemento distinto de null y dicho array debería ser de largo 9. Lo anterior lo implemento en el primer **if** que se encuentra dentro del primer **else** en el siguiente código:\n\n```js\nif (winner) {\n  status = \"🏆 Winner: \" + `\u003cstrong\u003e${winner}\u003c/strong\u003e`;\n} else {\n  if (current.squares.filter((e) =\u003e e).length == 9) {\n    status = \"Draw ⚖️\";\n  } else {\n    status =\n      \"Next player: \" +\n      (this.state.xIsNext ? \"\u003cstrong\u003eX\u003c/strong\u003e\" : \"\u003cstrong\u003eO\u003c/strong\u003e\");\n  }\n}\n```\n\nA continuación muestro cuando existe un empate:\n\n![Tablero con empate](./screenshots/draw.webp)\n\n## Current React Tutorial: 1.For the current move only, show “You are at move #…” instead of a button\n\nLa propiedad de estado **indexStep** se setea a un nuevo valor en dos ocasiones:\n\n1-Cuando se hace click en algún item de la lista de movimientos\n\n2-Cuando se realiza alguna jugada en el tablero\n\nPor lo tanto, utilizando dicha propiedad de estado mostraré un tag div con estilos en reemplazo de un botón en la lista con el texto **You are in move #** en el índice de la lista igual al valor de la propiedad de estado **indexStep**:\n\n```jsx\nconst stylesButton =\n  this.state.indexSeleccionado == move\n    ? styles[\"button-list-selected\"]\n    : undefined;\nreturn (\n  \u003cli key={move}\u003e\n    {move == this.state.indexStep ? (\n      \u003cdiv\n        className={`${styles[\"actual-list-time\"]}\n            ${stylesButton}`}\n        onClick={() =\u003e this.jumpTo(move)}\n      \u003e\n        You are in move {move + 1}\n        {move\n          ? \"- Position: \" +\n            indexElementDifferent(history[move - 1].squares, step.squares).join(\n              \",\"\n            )\n          : \"\"}\n      \u003c/div\u003e\n    ) : (\n      \u003cbutton\n        className={`${styles[\"button-list_time\"]}\n            ${stylesButton}`}\n        onClick={() =\u003e this.jumpTo(move)}\n      \u003e\n        {desc}\n        {move\n          ? \"- Position: \" +\n            indexElementDifferent(history[move - 1].squares, step.squares).join(\n              \",\"\n            )\n          : \"\"}\n      \u003c/button\u003e\n    )}\n  \u003c/li\u003e\n);\n```\n\nCuando se hace click en algún elemento de la lista se aplican estilos para esa acción en base a lo realizado en mi solución del ejercicio dos del tutorial legacy y además se aplican estilos en base a lo realizado en el ejercicio actual lo que provoca que existan **2** estilos aplicados a la vez. En este caso se aplican los estilos establecidos por cascada en CSS:\n\n```css\n.actual-list-time {\n  padding: 5px;\n  background-color: orange;\n  border: 1px solid black;\n  cursor: pointer;\n  border-radius: 5px;\n  font-weight: 600;\n}\n.button-list-selected {\n  background-color: blue;\n  color: white;\n}\n```\n\nEs decir, cuando existan las dos clases en el mismo elemento la que primará será la última clase que en este caso es la clase **button-list-selected**.\n\n![Estilos simultáneos](./screenshots/styles_selected_list_item.png)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwaldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fall_solution_challenges_legacy_and_current_react_tutorial/lists"}