From b3238377189240c728395db7d1ebf9f3a372c72f Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Tue, 13 Jun 2023 15:36:33 -0400 Subject: [PATCH 01/23] refactor: use proper react native components --- solutions/react-native-simple-counter.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/solutions/react-native-simple-counter.js b/solutions/react-native-simple-counter.js index 13d48fb..26c4822 100644 --- a/solutions/react-native-simple-counter.js +++ b/solutions/react-native-simple-counter.js @@ -1,18 +1,19 @@ import React, { useState } from "react" -import { Text, View, StyleSheet } from "react-native" +import { Text, View, StyleSheet, Button } from "react-native" const SimpleCounter = () => { const [count, setCount] = useState(0) const increment = () => setCount(count + 1) + return ( - button count: {count} + button count: {count} - + ) } From c86e0b15d3768309c56fc349d4d44a79ade7bd0c Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Tue, 13 Jun 2023 15:37:24 -0400 Subject: [PATCH 02/23] chore: typo --- solutions/context-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/context-api.js b/solutions/context-api.js index 246e596..ef025b6 100644 --- a/solutions/context-api.js +++ b/solutions/context-api.js @@ -29,7 +29,7 @@ function MainSection() { } return (
-

{`Favorite programing language: ${language}`}

+

{`Favorite programming language: ${language}`}

From f6579447d081b2e0f82465b9730ff92a031e0b09 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Tue, 13 Jun 2023 15:42:22 -0400 Subject: [PATCH 03/23] refactor: make code more DRY with onChange function --- solutions/phone-book.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/solutions/phone-book.js b/solutions/phone-book.js index 3394f85..67b94bf 100644 --- a/solutions/phone-book.js +++ b/solutions/phone-book.js @@ -52,6 +52,9 @@ function PhoneBookForm({ addEntryToPhoneBook }) { const [formState, dispatch] = useReducer(formReducer, initialFormState) + const onChange = ({ target: { name, value } }) => + dispatch({ type: name, payload: value }) + return (
{ @@ -68,9 +71,7 @@ function PhoneBookForm({ addEntryToPhoneBook }) { className="userFirstname" name="userFirstname" type="text" - onChange={({ target: { name, value } }) => - dispatch({ type: name, payload: value }) - } + onChange={onChange} value={formState.userFirstname} />
@@ -81,9 +82,7 @@ function PhoneBookForm({ addEntryToPhoneBook }) { className="userLastname" name="userLastname" type="text" - onChange={({ target: { name, value } }) => - dispatch({ type: name, payload: value }) - } + onChange={onChange} value={formState.userLastname} />
@@ -94,9 +93,7 @@ function PhoneBookForm({ addEntryToPhoneBook }) { className="userPhone" name="userPhone" type="text" - onChange={({ target: { name, value } }) => - dispatch({ type: name, payload: value }) - } + onChange={onChange} value={formState.userPhone} />
From 82c16061452cbd0913825d8f846d0a3c31f179c6 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Tue, 13 Jun 2023 15:57:22 -0400 Subject: [PATCH 04/23] refactor: function name and return value --- solutions/typescript-button-toggle.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/typescript-button-toggle.ts b/solutions/typescript-button-toggle.ts index d3afd05..618fc2e 100644 --- a/solutions/typescript-button-toggle.ts +++ b/solutions/typescript-button-toggle.ts @@ -4,12 +4,12 @@ import ReactDOM from "react-dom" function Toggle(): ReactNode { const [toggle, setToggle] = useState(true) - function handleClick() { + function onClick(): void { setToggle(!toggle) } return ( - ) From f0bf0f5ee92d5645c63afb156454a4dbd74bd87f Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Tue, 13 Jun 2023 15:57:34 -0400 Subject: [PATCH 05/23] chore: update README --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0baaa60..f296d5d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,17 @@ ![coderbyte](https://user-images.githubusercontent.com/22095244/211191145-4aa983e0-3efa-440d-accd-df48853f572d.png) - # Coderbyte React Challenges -- This repo contains my solutions for the React Interview Kit challenges. +- This repo contains my solutions for the React Interview Kit challenges. -- All solutions received a 10/10 score. +- All solutions received a 10/10 score. -- Feel free to use any of my solutions for yourself! +- Feel free to use any of my solutions for yourself! ### Update 1/8/23 -I added the missing solutions to the newer challenges Coderbyte made for React/React Native since I first created this repo. As of now, all challenges are solved. Since this repo seems to be my most popular repo, I will try to periodicallly check and update it with more solutions if Coderbyte decides to add more React challenges. + +I added the missing solutions to the newer challenges Coderbyte made for React/React Native since I first created this repo. As of now, all challenges are solved. Since this repo seems to be popular, I will try to periodically check and update it with more solutions if Coderbyte decides to add more React challenges. + +### Update 6/13/23 + +Refactored a few solutions! From 65e7153043223bc8428c760264571fbd781595cd Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 21 Sep 2023 02:08:31 -0400 Subject: [PATCH 06/23] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f296d5d..c5c5bc2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -![coderbyte](https://user-images.githubusercontent.com/22095244/211191145-4aa983e0-3efa-440d-accd-df48853f572d.png) - # Coderbyte React Challenges -- This repo contains my solutions for the React Interview Kit challenges. +- This repo contains my solutions for the [React Interview Kit](https://coderbyte.com/interview-kit/react) challenges. - All solutions received a 10/10 score. @@ -15,3 +13,6 @@ I added the missing solutions to the newer challenges Coderbyte made for React/R ### Update 6/13/23 Refactored a few solutions! + +### Update 9/21/23 +Slight editing of README. From 7fe78630b615741f6356c9a36b2161857aff94f5 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 14:51:39 -0500 Subject: [PATCH 07/23] refactor: phone-book.js solution --- solutions/phone-book.js | 51 +++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/solutions/phone-book.js b/solutions/phone-book.js index 67b94bf..c5b73d0 100644 --- a/solutions/phone-book.js +++ b/solutions/phone-book.js @@ -1,5 +1,5 @@ -import React, { useState, useReducer } from "react" -import ReactDOM from "react-dom" +import React, { useState, useReducer, useCallback } from "react" +import { createRoot } from "react-dom/client" const style = { table: { @@ -34,7 +34,7 @@ const style = { }, } -function PhoneBookForm({ addEntryToPhoneBook }) { +function PhoneBookForm({ entries, setEntries }) { const initialFormState = { userFirstname: "Coder", userLastname: "Byte", @@ -55,6 +55,24 @@ function PhoneBookForm({ addEntryToPhoneBook }) { const onChange = ({ target: { name, value } }) => dispatch({ type: name, payload: value }) + const addEntryToPhoneBook = useCallback(() => { + const { userFirstname, userLastname, userPhone } = formState + const newEntries = [ + ...entries, + { userFirstname, userLastname, userPhone }, + ] + const newSortedEntries = newEntries.sort((a, b) => { + const userLastnameA = a.userLastname.toLowerCase() + const userLastnameB = b.userLastname.toLowerCase() + return userLastnameA < userLastnameB + ? -1 + : userLastnameA > userLastnameB + ? 1 + : 0 + }) + setEntries(newSortedEntries) + }, [formState]) + return ( { @@ -132,34 +150,13 @@ function InformationTable({ entries }) { function Application() { const [entries, setEntries] = useState([]) - - const addEntryToPhoneBook = ({ - userFirstname, - userLastname, - userPhone, - }) => { - const newEntries = [ - ...entries, - { userFirstname, userLastname, userPhone }, - ] - const newSortedEntries = newEntries.sort((a, b) => { - const userLastnameA = a.userLastname.toLowerCase() - const userLastnameB = b.userLastname.toLowerCase() - return userLastnameA < userLastnameB - ? -1 - : userLastnameA > userLastnameB - ? 1 - : 0 - }) - setEntries(newSortedEntries) - } - return (
- +
) } -ReactDOM.render(, document.getElementById("root")) +const root = createRoot(document.getElementById("root")) +root.render() From 4f1e5808a675efa6c6026f515cc6c30924ecb4c9 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 15:05:24 -0500 Subject: [PATCH 08/23] refactor: simple-counter.js --- solutions/simple-counter.js | 45 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/solutions/simple-counter.js b/solutions/simple-counter.js index c4c92b4..ebea834 100644 --- a/solutions/simple-counter.js +++ b/solutions/simple-counter.js @@ -1,30 +1,25 @@ -import React, { useState } from 'react'; -import ReactDOM from 'react-dom'; +import React, { useState } from "react" +import { createRoot } from "react-dom/client" const Counter = () => { - const [count, setCount] = useState(0); + const [count, setCount] = useState(0) - increment = () => { - setCount(prevCount => prevCount + 1); - }; + const increment = () => { + setCount(prevCount => prevCount + 1) + } - return ( -
-

- Button Count: - {count} -

- -
- ); -}; + return ( +
+

+ {`Button Count: `} + {count} +

+ +
+ ) +} -ReactDOM.render( - , - document.getElementById('root') -); \ No newline at end of file +const root = createRoot(document.getElementById("root")) +root.render() From 5fa3a960d946a3bc00874eafc3ab56d99b785f80 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 15:14:31 -0500 Subject: [PATCH 09/23] refactor: button-toggle.js --- solutions/button-toggle.js | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/solutions/button-toggle.js b/solutions/button-toggle.js index d530905..b75f0f1 100644 --- a/solutions/button-toggle.js +++ b/solutions/button-toggle.js @@ -1,22 +1,19 @@ -import React, { useState } from 'react'; -import ReactDOM from 'react-dom'; +import React, { useState } from "react" +import { createRoot } from "react-dom/client" const Toggle = () => { + const [toggle, setToggle] = useState(false) - const [toggle, setToggle] = useState(false); - - const handleClick = () => { - setToggle(!toggle); - }; + const handleClick = () => { + setToggle(!toggle) + } return ( - - ); -}; + + ) +} -ReactDOM.render( - , - document.getElementById('root') -); \ No newline at end of file +const root = createRoot(document.getElementById("root")) +root.render() From 1744da67daf9b18ca3603224fbbfee31608ebf3f Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 16:07:47 -0500 Subject: [PATCH 10/23] refactor: list.js --- solutions/list.js | 58 ++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/solutions/list.js b/solutions/list.js index 820a0d2..432df61 100644 --- a/solutions/list.js +++ b/solutions/list.js @@ -1,43 +1,33 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React from "react" +import { createRoot } from "react-dom/client" const data = [ - { name: 'Daniel', age: 25 }, - { name: 'John', age: 24 }, - { name: 'Jen', age: 31 }, -]; + { name: "Daniel", age: 25 }, + { name: "John", age: 24 }, + { name: "Jen", age: 31 }, +] -const DataItem = ({ name, age}) => { - - return ( +const DataItem = ({ name, age }) => (
  • - {name}{` `} - {age} + {`${name} `} + {age}
  • - ); -}; +) -const DataList = () => { - - return ( +const DataList = ({ data }) => (
    -

    Data List

    -
      - {data.map((dataItem, index) => { - return ( - - ); - })} -
    +

    Data List

    +
      + {data.map((dataItem, index) => ( + + ))} +
    - ); -}; +) -ReactDOM.render( - , - document.getElementById('root') -); \ No newline at end of file +const root = createRoot(document.getElementById("root")) +root.render() From 32767c3fd0f134afcaecebd383bd75ebfe27c1e5 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 16:56:49 -0500 Subject: [PATCH 11/23] refactor: context-api.js --- solutions/context-api.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/solutions/context-api.js b/solutions/context-api.js index ef025b6..ed846af 100644 --- a/solutions/context-api.js +++ b/solutions/context-api.js @@ -1,5 +1,5 @@ import React, { useState, createContext, useContext } from "react" -import ReactDOM from "react-dom" +import { createRoot } from "react-dom/client" const languages = ["JavaScript", "Python"] const LanguageContext = createContext({ @@ -8,25 +8,14 @@ const LanguageContext = createContext({ setLanguage: () => {}, }) -function App() { - const [language, setLanguage] = useState(languages[0]) - return ( - - - - ) -} - -function MainSection() { +const MainSection = () => { const { languages, language, setLanguage } = useContext(LanguageContext) const currentIndex = languages.indexOf(language) - const toggleLanguage = () => { - if (currentIndex === languages.length - 1) { - setLanguage(languages[0]) - } else { - setLanguage(languages[currentIndex + 1]) - } - } + const toggleLanguage = () => + currentIndex === languages.length - 1 + ? setLanguage(languages[0]) + : setLanguage(languages[currentIndex + 1]) + return (

    {`Favorite programming language: ${language}`}

    @@ -37,4 +26,14 @@ function MainSection() { ) } -ReactDOM.render(, document.getElementById("root")) +const App = () => { + const [language, setLanguage] = useState(languages[0]) + return ( + + + + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From ef699b62ea5f4e5457199d5e9919caf99b1bb2fb Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 17:25:29 -0500 Subject: [PATCH 12/23] refactor: typescript-button-toggle.ts --- solutions/typescript-button-toggle.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/solutions/typescript-button-toggle.ts b/solutions/typescript-button-toggle.ts index 618fc2e..7cc1f07 100644 --- a/solutions/typescript-button-toggle.ts +++ b/solutions/typescript-button-toggle.ts @@ -1,18 +1,15 @@ import React, { useState, ReactNode } from "react" -import ReactDOM from "react-dom" +import { createRoot } from "react-dom/client" -function Toggle(): ReactNode { +const Toggle: ReactNode = () => { const [toggle, setToggle] = useState(true) - function onClick(): void { + const onClick = (): void => { setToggle(!toggle) } - return ( - - ) + return } -ReactDOM.render(, document.getElementById("root")) +const root = createRoot(document.getElementById("root")) +root.render() From eb4a64ddc11fa2be90e074ce6a816ff925bf0148 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Thu, 18 Jan 2024 17:53:52 -0500 Subject: [PATCH 13/23] refactor: react-native-simple-counter.js --- solutions/react-native-simple-counter.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solutions/react-native-simple-counter.js b/solutions/react-native-simple-counter.js index 26c4822..c6b6dbe 100644 --- a/solutions/react-native-simple-counter.js +++ b/solutions/react-native-simple-counter.js @@ -1,5 +1,5 @@ import React, { useState } from "react" -import { Text, View, StyleSheet, Button } from "react-native" +import { Text, View, StyleSheet } from "react-native" const SimpleCounter = () => { const [count, setCount] = useState(0) @@ -9,11 +9,11 @@ const SimpleCounter = () => { return ( - button count: {count} + button count: {count} - + ) } @@ -26,7 +26,7 @@ const styles = StyleSheet.create({ }, counter: { textAlign: "center", - marginVertical: 10, + marginVertical: 20, }, }) From 0f23e6a04ef7be236886c47c54e7a9ea14ad9585 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:16:05 -0500 Subject: [PATCH 14/23] refactor: tic-tac-toe.js --- solutions/tic-tac-toe.js | 424 ++++++++++++++++----------------------- 1 file changed, 169 insertions(+), 255 deletions(-) diff --git a/solutions/tic-tac-toe.js b/solutions/tic-tac-toe.js index 38289ee..5b7e8ee 100644 --- a/solutions/tic-tac-toe.js +++ b/solutions/tic-tac-toe.js @@ -1,288 +1,202 @@ -import React, { useState, useEffect } from 'react'; -import ReactDOM from 'react-dom'; +import React, { useState } from "react" +import { createRoot } from "react-dom/client" const rowStyle = { - display: 'flex' + display: "flex", } const squareStyle = { - 'width':'60px', - 'height':'60px', - 'backgroundColor': '#ddd', - 'margin': '4px', - 'display': 'flex', - 'justifyContent': 'center', - 'alignItems': 'center', - 'fontSize': '20px', - 'color': 'white', - 'cursor': 'pointer', + width: "60px", + height: "60px", + backgroundColor: "#ddd", + margin: "4px", + display: "flex", + justifyContent: "center", + alignItems: "center", + fontSize: "20px", + color: "white", +} + +const disabledSquareStyle = { + ...squareStyle, + cursor: "not-allowed", } const boardStyle = { - 'backgroundColor': '#eee', - 'width': '208px', - 'alignItems': 'center', - 'justifyContent': 'center', - 'display': 'flex', - 'flexDirection': 'column', - 'border': '3px #eee solid' + backgroundColor: "#eee", + width: "208px", + alignItems: "center", + justifyContent: "center", + display: "flex", + flexDirection: "column", + border: "3px #eee solid", } const containerStyle = { - 'display': 'flex', - 'alignItems': 'center', - 'flexDirection': 'column' + display: "flex", + alignItems: "center", + flexDirection: "column", } const instructionsStyle = { - 'marginTop': '5px', - 'marginBottom': '5px', - 'fontWeight': 'bold', - 'fontSize': '16px', + marginTop: "5px", + marginBottom: "5px", + fontWeight: "bold", + fontSize: "16px", } const buttonStyle = { - 'marginTop': '15px', - 'marginBottom': '16px', - 'width': '80px', - 'height': '40px', - 'backgroundColor': '#8acaca', - 'color': 'white', - 'fontSize': '16px', - 'cursor': 'pointer', + marginTop: "15px", + marginBottom: "16px", + width: "80px", + height: "40px", + backgroundColor: "#8acaca", + color: "white", + fontSize: "16px", } -const Square = ({playerXSquares, playerOSquares, handleClick, value, disabled }) => { - return ( -
    { - if (!disabled) { - handleClick(value) - } - }} - > - - {playerXSquares.indexOf(value) > -1 ? 'X' : playerOSquares.indexOf(value) > -1 ? 'O' : ''} - -
    - ); -}; +const Square = ({ value, onClick, winner }) => { + return ( + + ) +} const Board = () => { - const [currentPlayer, setCurrentPlayer] = useState('player X'); - const [winner, setWinner] = useState('None') - const [playerXSquares, setPlayerXSquares] = useState([]); - const [playerOSquares, setPlayerOSquares] = useState([]); - - const handleClick = value => { - if (currentPlayer === 'player X') { - setPlayerXSquares([...playerXSquares, value]); - setCurrentPlayer('player O'); - } else { - setPlayerOSquares([...playerOSquares, value]); - setCurrentPlayer('player X'); - } - } - - const determineWinner = (playerXSquares, playerOSquares) => { - function checkRows() { - if ( - (playerXSquares.includes(0) && playerXSquares.includes(1) && playerXSquares.includes(2)) || - (playerXSquares.includes(3) && playerXSquares.includes(4) && playerXSquares.includes(5)) || - (playerXSquares.includes(6) && playerXSquares.includes(7) && playerXSquares.includes(8)) - ) { - return setWinner('Player X'); - } - - if ( - (playerOSquares.includes(0) && playerOSquares.includes(1) && playerOSquares.includes(2)) || - (playerOSquares.includes(3) && playerOSquares.includes(4) && playerOSquares.includes(5)) || - (playerOSquares.includes(6) && playerOSquares.includes(7) && playerOSquares.includes(8)) - ) { - return setWinner('Player O'); - } + const [player, setPlayer] = useState("X") + const [winner, setWinner] = useState("None") + const [board, setBoard] = useState(() => Array(9).fill(null)) + + const matches = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6], + ] + + const checkWinner = newBoard => { + for (let i = 0; i < matches.length; i++) { + const [a, b, c] = matches[i] + if ( + newBoard[a] === player && + newBoard[b] === player && + newBoard[c] === player + ) { + return true + } + } + return false } - function checkColumns() { - if ( - (playerXSquares.includes(0) && playerXSquares.includes(3) && playerXSquares.includes(6)) || - (playerXSquares.includes(1) && playerXSquares.includes(4) && playerXSquares.includes(7)) || - (playerXSquares.includes(2) && playerXSquares.includes(5) && playerXSquares.includes(8)) - ) { - return setWinner('Player X'); - } - - if ( - (playerOSquares.includes(0) && playerOSquares.includes(3) && playerOSquares.includes(6)) || - (playerOSquares.includes(1) && playerOSquares.includes(4) && playerOSquares.includes(7)) || - (playerOSquares.includes(2) && playerOSquares.includes(5) && playerOSquares.includes(8)) - ) { - return setWinner('Player O'); - } - } + const onClick = index => { + const newBoard = [...board] + newBoard[index] = player + setBoard(newBoard) - function checkDiagonals() { - if (playerXSquares.includes(4)) { - if ((playerXSquares.includes(0) && playerXSquares.includes(8)) || (playerXSquares.includes(2) && playerXSquares.includes(6))) { - return setWinner('Player X'); + if (checkWinner(newBoard)) { + setWinner(player) + } else { + setPlayer(player === "X" ? "O" : "X") } - } - if (playerOSquares.includes(4)) { - if ((playerOSquares.includes(0) && playerOSquares.includes(8)) || (playerOSquares.includes(2) && playerOSquares.includes(6))) { - return setWinner('Player O'); - } - } } - if (winner === 'None') { - checkRows(); - checkColumns(); - checkDiagonals(); + const onReset = () => { + setBoard(Array(9).fill(null)) + setPlayer("X") + setWinner("None") } - } - - - const reset = () => { - setCurrentPlayer('Player X'); - setPlayerXSquares([]); - setPlayerOSquares([]); - setWinner('None'); - } - useEffect(() => { - determineWinner(playerXSquares, playerOSquares); - }, [playerXSquares, playerOSquares]); - - return ( -
    -
    - Next player: {currentPlayer === 'Player X' ? 'Player O' : 'Player X'} -
    -
    - Winner: {winner} -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - + return ( +
    +
    + Next player: {player === "X" ? "O" : "X"} +
    +
    + Winner: {winner !== "None" && winner} +
    + +
    +
    + onClick(0)} + winner={winner} + /> + onClick(1)} + winner={winner} + /> + onClick(2)} + winner={winner} + /> +
    +
    + onClick(3)} + winner={winner} + /> + onClick(4)} + winner={winner} + /> + onClick(5)} + winner={winner} + /> +
    +
    + onClick(6)} + winner={winner} + /> + onClick(7)} + winner={winner} + /> + onClick(8)} + winner={winner} + /> +
    +
    -
    -
    - ); -}; + ) +} const Game = () => { - return ( -
    -
    - -
    -
    - ); -}; + return ( +
    +
    + +
    +
    + ) +} -ReactDOM.render( - , - document.getElementById('root') -); \ No newline at end of file +const root = createRoot(document.getElementById("root")) +root.render() From a6d33d57a9388bd92e398ed2b6bc8839db3bd31c Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:20:32 -0500 Subject: [PATCH 15/23] chore: change file extensions from js/ts to jsx/tsx --- solutions/{button-toggle.js => button-toggle.jsx} | 0 solutions/{context-api.js => context-api.jsx} | 0 solutions/{list.js => list.jsx} | 0 solutions/{phone-book.js => phone-book.jsx} | 0 ...t-native-simple-counter.js => react-native-simple-counter.jsx} | 0 solutions/{simple-counter.js => simple-counter.jsx} | 0 solutions/{tic-tac-toe.js => tic-tac-toe.jsx} | 0 .../{typescript-button-toggle.ts => typescript-button-toggle.tsx} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename solutions/{button-toggle.js => button-toggle.jsx} (100%) rename solutions/{context-api.js => context-api.jsx} (100%) rename solutions/{list.js => list.jsx} (100%) rename solutions/{phone-book.js => phone-book.jsx} (100%) rename solutions/{react-native-simple-counter.js => react-native-simple-counter.jsx} (100%) rename solutions/{simple-counter.js => simple-counter.jsx} (100%) rename solutions/{tic-tac-toe.js => tic-tac-toe.jsx} (100%) rename solutions/{typescript-button-toggle.ts => typescript-button-toggle.tsx} (100%) diff --git a/solutions/button-toggle.js b/solutions/button-toggle.jsx similarity index 100% rename from solutions/button-toggle.js rename to solutions/button-toggle.jsx diff --git a/solutions/context-api.js b/solutions/context-api.jsx similarity index 100% rename from solutions/context-api.js rename to solutions/context-api.jsx diff --git a/solutions/list.js b/solutions/list.jsx similarity index 100% rename from solutions/list.js rename to solutions/list.jsx diff --git a/solutions/phone-book.js b/solutions/phone-book.jsx similarity index 100% rename from solutions/phone-book.js rename to solutions/phone-book.jsx diff --git a/solutions/react-native-simple-counter.js b/solutions/react-native-simple-counter.jsx similarity index 100% rename from solutions/react-native-simple-counter.js rename to solutions/react-native-simple-counter.jsx diff --git a/solutions/simple-counter.js b/solutions/simple-counter.jsx similarity index 100% rename from solutions/simple-counter.js rename to solutions/simple-counter.jsx diff --git a/solutions/tic-tac-toe.js b/solutions/tic-tac-toe.jsx similarity index 100% rename from solutions/tic-tac-toe.js rename to solutions/tic-tac-toe.jsx diff --git a/solutions/typescript-button-toggle.ts b/solutions/typescript-button-toggle.tsx similarity index 100% rename from solutions/typescript-button-toggle.ts rename to solutions/typescript-button-toggle.tsx From b8c5bd4ebf374b017b7ae62672c75e245358fdbe Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:29:59 -0500 Subject: [PATCH 16/23] feat: add color-dropdown.jsx solution --- solutions/color-dropdown.jsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 solutions/color-dropdown.jsx diff --git a/solutions/color-dropdown.jsx b/solutions/color-dropdown.jsx new file mode 100644 index 0000000..17e5e89 --- /dev/null +++ b/solutions/color-dropdown.jsx @@ -0,0 +1,21 @@ +import React, { useState } from "react" +import { createRoot } from "react-dom/client" + +function ColorSelector() { + const colors = { red: "Red", blue: "Blue", green: "Green" } + const [color, setColor] = useState(colors.red) + const onChange = e => setColor(e.target.value) + return ( + <> + + {color &&

    {`You have selected: ${color}`}

    } + + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From 04d8498b4dc620c5d9522fef7252220defefeeb7 Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:30:26 -0500 Subject: [PATCH 17/23] feat: add live-paragraph.jsx solution --- solutions/live-paragraph.jsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 solutions/live-paragraph.jsx diff --git a/solutions/live-paragraph.jsx b/solutions/live-paragraph.jsx new file mode 100644 index 0000000..e5b9ea9 --- /dev/null +++ b/solutions/live-paragraph.jsx @@ -0,0 +1,19 @@ +import React, { useState } from "react" +import { createRoot } from "react-dom/client" + +function LiveText() { + const [text, setText] = useState("") + + const onChange = ({ target: { value } }) => { + setText(value) + } + return ( + <> + +

    {text}

    + + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From 036d970d758af3dba98ddf1211504c0a54560a2b Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:31:31 -0500 Subject: [PATCH 18/23] feat: add quiz-builder.jsx solution --- solutions/quiz-builder.jsx | 130 +++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 solutions/quiz-builder.jsx diff --git a/solutions/quiz-builder.jsx b/solutions/quiz-builder.jsx new file mode 100644 index 0000000..6d96c0f --- /dev/null +++ b/solutions/quiz-builder.jsx @@ -0,0 +1,130 @@ +import React, { useState, useMemo } from "react" +import { createRoot } from "react-dom/client" + +const style = { + container: { + padding: "20px", + border: "1px solid #E0E0E0", + borderRadius: "15px", + width: "max-content", + marginBottom: "40px", + }, + question: { + fontWeight: "bold", + marginBottom: "10px", + }, + options: { + marginBottom: "5px", + }, + button: { + marginTop: "10px", + padding: "10px 15px", + border: "none", + backgroundColor: "#007BFF", + color: "#FFF", + fontSize: "14px", + borderRadius: "5px", + cursor: "pointer", + }, + feedback: { + marginTop: "10px", + fontSize: "14px", + }, +} + +const QuizOption = ({ option, index, answer, setAnswer }) => { + const onChange = ({ target: { value } }) => setAnswer(value) + return ( + <> + + + + ) +} + +function QuizApp() { + // do not modify the questions or answers below + const questions = useMemo( + () => [ + { + question: "What is the capital of France?", + options: ["London", "Paris", "Berlin", "Madrid"], + correct: "Paris", + }, + { + question: "What is the capital of Germany?", + options: ["Berlin", "Munich", "Frankfurt", "Hamburg"], + correct: "Berlin", + }, + ], + [] + ) + + const questionsTotal = useMemo(() => questions.length, [questions]) + + const [questionsIndex, setQuestionsIndex] = useState(0) + const [score, setScore] = useState(0) + const [feedback, setFeedback] = useState(null) + const [answer, setAnswer] = useState(null) + const [completedQuiz, setCompletedQuiz] = useState(false) + + const submit = () => { + if (answer === questions[questionsIndex].correct) { + setScore(score + 1) + setFeedback("Correct!") + } else { + setFeedback("Incorrect!") + } + + if (questionsIndex === questionsTotal - 1) { + setCompletedQuiz(true) + } else { + setQuestionsIndex(questionsIndex + 1) + setAnswer(null) + } + } + + return ( +
    +
    + {`${questions[questionsIndex].question}`} +
    +
    + {questions[questionsIndex].options.map((option, index) => ( + + ))} +
    + +
    + {questionsIndex !== 0 && !completedQuiz && `${feedback}`} +
    +
    + {completedQuiz && + `Quiz complete! You scored ${score} out of ${questions.length}!`} +
    +
    + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From 33df2b613d44ff9c5372a5c194c5d7dbd8009c5a Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 01:32:40 -0500 Subject: [PATCH 19/23] feat: add letter-tiles.jsx solution --- solutions/letter-tiles.jsx | 83 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 solutions/letter-tiles.jsx diff --git a/solutions/letter-tiles.jsx b/solutions/letter-tiles.jsx new file mode 100644 index 0000000..b8d6e81 --- /dev/null +++ b/solutions/letter-tiles.jsx @@ -0,0 +1,83 @@ +import React, { useState, useCallback, useMemo } from "react" +import { createRoot } from "react-dom/client" + +const style = { + letterContainer: { + overflow: "auto", + marginBottom: "10px", + display: "flex", + flexWrap: "wrap", + justifyContent: "center", + alignItems: "center", + }, + letter: { + float: "left", + padding: "10px 10px", + background: "#c9e4ed", + borderRadius: "5px", + marginRight: "5px", + marginTop: "5px", + cursor: "pointer", + }, + outputString: { + marginTop: "20px", + textAlign: "center", + }, +} + +const Tile = ({ letter, outputArray, setOutputArray, tally, setTally }) => { + const onClick = useCallback(() => { + if (!tally[letter]) { + setTally({ ...tally, [`${letter}`]: 1 }) + setOutputArray([...outputArray, letter]) + } else if (tally[`${letter}`] && tally[`${letter}`] === 2) { + setTally({ ...tally, [`${letter}`]: 0 }) + const slicedArray = outputArray.slice(0, outputArray.length - 2) + setOutputArray([...slicedArray, "_"]) + } else { + setTally({ ...tally, [`${letter}`]: tally[`${letter}`] + 1 }) + setOutputArray([...outputArray, letter]) + } + }, [letter, outputArray, setOutputArray, tally, setTally]) + + return ( + + ) +} + +const Application = () => { + const [outputArray, setOutputArray] = useState([]) + const [tally, setTally] = useState({}) + const alphabetArray = useMemo(() => { + let arr = [] + for (let i = 65; i <= 90; i++) { + const char = String.fromCharCode(i) + arr.push(char) + } + return arr + }, []) + return ( +
    + +
    + {outputArray.join("")} +
    +
    + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From 0e687af776dd899ef69275cc0f42a60a95a79fcb Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 04:39:35 -0500 Subject: [PATCH 20/23] feat: add weather-dashboard.jsx solution --- solutions/weather-dashboard.jsx | 121 ++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 solutions/weather-dashboard.jsx diff --git a/solutions/weather-dashboard.jsx b/solutions/weather-dashboard.jsx new file mode 100644 index 0000000..677f148 --- /dev/null +++ b/solutions/weather-dashboard.jsx @@ -0,0 +1,121 @@ +import React, { useState } from "react" +import { createRoot } from "react-dom/client" + +const style = { + marginTop: { + marginTop: "10px", + }, + marginRight: { + marginRight: "10px", + }, +} + +const WeatherDashboard = () => { + // instead of requesting data from an API, use this mock data + const mockWeatherData = { + "New York": { + temperature: "22°C", + humidity: "56%", + windSpeed: "15 km/h", + }, + "Los Angeles": { + temperature: "27°C", + humidity: "45%", + windSpeed: "10 km/h", + }, + London: { + temperature: "15°C", + humidity: "70%", + windSpeed: "20 km/h", + }, + } + + const defaultWeather = { + temperature: "", + humidity: "", + windSpeed: "", + } + + const [city, setCity] = useState("") + const [cache, setCache] = useState({}) + const [notFound, setNotFound] = useState(false) + const [previousSearches, setPreviousSearches] = useState([]) + const [weather, setWeather] = useState(defaultWeather) + + const mockFetchWeatherData = city => { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (mockWeatherData[city]) { + resolve(mockWeatherData[city]) + } else { + reject(new Error("City not found.")) + setNotFound(true) + setWeather(defaultWeather) + } + }, 500) + }) + } + + const search = async city => { + setNotFound(false) + + if (!city || city === "") { + setWeather(defaultWeather) + setNotFound(true) + return + } + + if (cache[city]) { + setWeather(cache[city]) + return + } + + try { + const data = await mockFetchWeatherData(city) + setCache({ ...cache, [city]: data }) + setWeather(data) + setPreviousSearches([...previousSearches, city]) + } catch { + throw new Error("Could not fetch weather data.") + } + } + + return ( +
    + setCity(e.target.value)} + /> + +
    +
    Temperature: {weather.temperature}
    +
    Humidity: {weather.humidity}
    +
    Wind Speed: {weather.windSpeed}
    + {notFound &&
    City not found.
    } +
    +
    + {previousSearches.length > 0 && + previousSearches.map((previousSearch, index) => ( + + ))} +
    +
    + ) +} + +const root = createRoot(document.getElementById("root")) +root.render() From 297afef2abd1881838cfc43e46c7904ca94696df Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 04:46:47 -0500 Subject: [PATCH 21/23] chore: update README --- README.md | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c5c5bc2..53930c1 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,43 @@ # Coderbyte React Challenges -- This repo contains my solutions for the [React Interview Kit](https://coderbyte.com/interview-kit/react) challenges. +- This repo contains my solutions for the [React & React Native challenges](https://coderbyte.com/challenges). - All solutions received a 10/10 score. - Feel free to use any of my solutions for yourself! -### Update 1/8/23 +## Updates -I added the missing solutions to the newer challenges Coderbyte made for React/React Native since I first created this repo. As of now, all challenges are solved. Since this repo seems to be popular, I will try to periodically check and update it with more solutions if Coderbyte decides to add more React challenges. +#### 1/8/23 -### Update 6/13/23 +Added missing solutions for the newer challenges Coderbyte released. -Refactored a few solutions! +#### 6/13/23 -### Update 9/21/23 -Slight editing of README. +Refactored a few solutions. + +#### 9/21/23 + +Slight editing of `README`. + +#### 1/20/24 + +- Refactored all previous solutions to use React 18 and use .jsx/.tsx file extensions +- Redid solution for `tictactoe.jsx` +- Added new solutions for the following challenges: + - `color-dropdown.jsx` + - `letter-tiles.jsx` + - `live-paragraph.jsx` + - `quiz-builder.jsx` + - `weather-dashboard.jsx` +- Updated `README`` + +## FAQ + +**Can you include the challenge's question in your solution?** + +Unfortunately, no since I don't want to violate Coderbyte's [Terms of Use](https://coderbyte.com/terms). My solutions are only meant as a resource to check against your own or just to study from in general! You'll need to pay for Coderbyte to see the questions to their code challenges. + +**Do you accept submissions for alternative solutions?** + +No, not at this time. I originally intended to use this repo as a way to keep a copy of my solutions I wrote when I ended my Coderbyte subscription. However, since this repo has grown in popularity, if there is more interest to open this repo up and accept alternative solution submissions, I may consider this! From cfaf4bf634f4746cbbf44d53ee955006554df18a Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 04:50:46 -0500 Subject: [PATCH 22/23] fix: syntax error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53930c1..d41a055 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Slight editing of `README`. - `live-paragraph.jsx` - `quiz-builder.jsx` - `weather-dashboard.jsx` -- Updated `README`` +- Updated `README` ## FAQ From c43e7e32dadfd52977d90e7d43606abc7c4d8ebd Mon Sep 17 00:00:00 2001 From: Kayla Kremer Date: Sat, 20 Jan 2024 05:29:28 -0500 Subject: [PATCH 23/23] refactor: remove unnecessary template literals --- solutions/letter-tiles.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solutions/letter-tiles.jsx b/solutions/letter-tiles.jsx index b8d6e81..8821b9c 100644 --- a/solutions/letter-tiles.jsx +++ b/solutions/letter-tiles.jsx @@ -28,14 +28,14 @@ const style = { const Tile = ({ letter, outputArray, setOutputArray, tally, setTally }) => { const onClick = useCallback(() => { if (!tally[letter]) { - setTally({ ...tally, [`${letter}`]: 1 }) + setTally({ ...tally, [letter]: 1 }) setOutputArray([...outputArray, letter]) - } else if (tally[`${letter}`] && tally[`${letter}`] === 2) { - setTally({ ...tally, [`${letter}`]: 0 }) + } else if (tally[letter] && tally[letter] === 2) { + setTally({ ...tally, [letter]: 0 }) const slicedArray = outputArray.slice(0, outputArray.length - 2) setOutputArray([...slicedArray, "_"]) } else { - setTally({ ...tally, [`${letter}`]: tally[`${letter}`] + 1 }) + setTally({ ...tally, [letter]: tally[letter] + 1 }) setOutputArray([...outputArray, letter]) } }, [letter, outputArray, setOutputArray, tally, setTally]) @@ -51,7 +51,7 @@ const Application = () => { const [outputArray, setOutputArray] = useState([]) const [tally, setTally] = useState({}) const alphabetArray = useMemo(() => { - let arr = [] + const arr = [] for (let i = 65; i <= 90; i++) { const char = String.fromCharCode(i) arr.push(char) pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy