https://github.com/andreafan123/react_coding_challenges
Here are React Challenges.
https://github.com/andreafan123/react_coding_challenges
react react-challenge
Last synced: 3 months ago
JSON representation
Here are React Challenges.
- Host: GitHub
- URL: https://github.com/andreafan123/react_coding_challenges
- Owner: AndreaFan123
- Created: 2022-08-23T06:39:46.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2022-09-26T14:33:20.000Z (over 3 years ago)
- Last Synced: 2024-04-28T02:11:43.338Z (almost 2 years ago)
- Topics: react, react-challenge
- Homepage:
- Size: 18.6 KB
- Stars: 2
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# React Coding Challenges
## Table of Contents
- [Convert some HTML to JSX](#challenge-1--convert-some-html-to-jsx)
- [Display array of users to browser](#challenge-2-display-array-of-users-to-browser)
- [Disable Button](#challenge-3-disable-button)
- [Two way data binding](#challenge-4-two-way-data-binding)
- [Show text ater typing](#challenge-5-show-text-after-typing)
- [Show and Hide](#challenge-6-show--hide)
- [Adding to an array](#challenge-7-adding-to-an-array)
- [Deleting item from an array](#challenge-8-deleting-item-from-an-array)
- [Accordion P1](#challenge-9-accordion-part-1)
- [Accordion P2 (Lifting State)](#challenge-10-accordion-part-2-lifting-state)
- [Synced inputs](#challenge-10-1-synced-inputs)
- [Filtering a list](#challenge-10-2-filtering-a-list)
- [Effects related challenges](#challenge-11-fetch-data-challenges-related-to-effects)
- [Mini challenge 1](#mini-challenge-1-updating-state-based-on-props-or-state)
- [Mini challenge 2](#mini-challenge-2-caching-expensive-calculations)
- [Passing pros](#challenge-12-passing-props)
- [Mini challenge 1](#mini-challenge-1--extract-a-component)
---
### Challenge 1 : Convert some HTML to JSX
> **Note**
> Review: What is JSX
>
> JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file.
>
> Rules:
>
> 1. **Return a single root element**
>
> JSX looks like HTML, but under the hood it is transformed into plain JavaScript objects. You can’t return two objects from a function without wrapping them into an array.
>
> 2. **Close all the tags**
>
> JSX requires tags to be explicitly closed: self-closing tags like `
` must become `
`
>
> 3. **CamelCase most of the things!**
Code
```js
export default function Bio() {
return (
Welcome to my website!
You can find my thoughts here.
And pictures of scientists!
);
}
```
Solution
- Add fragment
- Adjust tags
```js
export default function Bio() {
return (
<>
Welcome to my website!
You can find my thoughts here.
{" "}
And pictures
of scientists!
>
);
}
```
---
### Challenge 2: Display array of users to browser
- First to create a file called `users.js`
- [CodeSandbox](https://codesandbox.io/s/display-an-array-ntpnb0)
- Second to import `users` in `App.js`
> **Note**
>
> If we did not provide an unique key props to `li`, it will show warning like this `Warning: Each child in a list should have a unique "key" prop.`
>
> **Rules of keys**
>
> 1. Must be unique among siblings. However, it’s okay to use the same keys for JSX nodes in different arrays.
>
> 2. Must not change.Don’t generate them while rendering.
Code
```js
export const users = [
{
name: "John",
age: 12,
},
{
name: "Alex",
age: 32,
},
];
```
```js
import "./styles.css";
import { users } from "./users";
export default function App() {
return (
User Profiles
{users.map((user) => (
{user.name}: {user.age} years old
))}
);
}
```
---
### Challenge 3: Disable Button
- Set initial state as we need to monitor if there's any value.
- use `useState()` to set an initial value.
- [CodeSandbox](https://codesandbox.io/s/disable-submit-btn-9fste3?file=/src/App.js)
> **Note**
>
> Review: `useState()`
>
> `useState` is a React Hook that lets you add a state variable to your component.
> **Warning**
>
> Calling the set function does not change the current state in the already executing code, It only affects what useState will return starting from the next render.
>
> [React Docs - useState](https://beta.reactjs.org/apis/react/useState)
Code
```js
import { useState } from "react";
export default function App() {
// set value
const [inputTxt, setInputTxt] = useState("");
const handleChange = (e) => {
e.preventDefault();
setInputtxt(e.target.value);
};
return (
Submit
);
}
```
##
### Challenge 4: Two way data binding
- `useState()` to initialize value.
- [CodaSandbox](https://codesandbox.io/s/2-way-data-binding-kyh08q?file=/src/App.js)
Code
```js
import "./styles.css";
import { useState } from "react";
export default function App() {
const [txt, setTxt] = useState("");
const handleChnage = (e) => {
setTxt(e.target.value);
};
return (
{txt}
);
}
```
---
### Challenge 5: Show text after typing
- `useState()`
- `useEffect()`
- [CodeSandbox](https://codesandbox.io/s/show-value-after-typing-gsbvys)
Code
```js
import { useState, useEffect } from "react";
export default function App() {
// initial 2 states
const [text, setText] = useState("");
const [showText, setShowText] = useState("");
// use useEffect() and pass text as dependency
useEffect(() => {
const timeoutId = setTimeOut(() => {
setShowText(text);
}, 300);
return () => {
clearTimeout(timeoutId);
};
}, [text]);
return (
setTxt(e.target.value)}
/>
{showText}
);
}
```
---
### Challenge 6: Show / hide
- `useState()` to initial state as `true`.
- If `showContent` is `true`, then show content, otherwise, show a smiley face.
- [CodeSandbox](https://codesandbox.io/s/show-hide-2n6ej7?file=/src/App.js)
Code
```js
import { useState } from "react";
export default function App() {
const [showContent, setShowContent] = useState(true);
const handleClick = () => {
setShowContent(!showContent);
};
return (
{showContent ? "Hide Content" : "Show Content"}
{showContent ? Hello, I am here
: :)
}
);
}
```
---
### Challenge 7: Adding to an array
- First to initialize state for text.
- Second to initialize an empty array as we will be adding text inside it.
- Use speard operator instead of `push()` to add a todo.
> **Note**
>
> - Even an array is mutable, we better treat them as immutable when we store in state.
> - **Treat array in React as read-only**, meaning that we shouldn't assign an item inside an array or use methods like `pop()` or `push()`.
Code
```js
import { useState } from "react";
export default function App() {
const [todo, setTodo] = useState("");
const [todoLists, setTodoLists] = useState([]);
const handleChange = (e) => {
setTodo(e.target.value);
};
const handleClick = () => {
// set id = 0
let id = 0;
// clear input after adding
setTodo("");
setTodoLists([...todoLists, { id: id++, todo: todo }]);
};
render(
Add
{todoLists.map((todoList) => (
- {todoList.todo}
))}
);
}
```
---
### Challenge 8: Deleting item from an array
- `filter()` creates a shadow copy of portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.
- We use `filter()` instead of `splice()` because `filter()` returns a new array, and it won't change the origin one.
- [CodeSandbox](https://codesandbox.io/s/removing-item-from-an-array-0k9jee?file=/src/App.js)
Code
```js
import "./styles.css";
import { useState } from "react";
export default function App() {
const [todo, setTodo] = useState("");
const [todoLists, setTodoLists] = useState([]);
const handleChange = (e) => {
setTodo(e.target.value);
};
const handleAdd = () => {
let id = 0;
setTodo("");
setTodoLists([...todoLists, { id: id++, todo: todo }]);
};
return (
Add
{todoLists.map((todoList) => (
<>
- {todoList.todo}
{
setTodoLists(todoLists.filter((t) => t.id !== todoList.id));
}}
>
Delete
>
))}
);
}
```
---
### Challenge 9: Accordion Part 1
- feature: User can click `button` to show content.
- What kind of component do we need?
- `Accordion.js` as parent component that can contain children component and pass data.
- `Panel.js` as child component, here we display data passed from parent component.
- Here we will add a button so that user can click for showing content.
- [CodeSanbox](https://codesandbox.io/s/accordion-part-1-0syiz2?file=/src/Panel.js)
- In this challenge, panels are independent, you won't be seeing they both show in the same time when clicking the `show` button.
- Next, we will need to tweak `Accordion` a bit as we want the only one panel is expanded at any given time, and the other one will be hidden.
Code
```js
// App.js
import Accordion from "./Accordion";
export default function App() {
return ;
}
```
```js
// Accordion.js
import Panel from "./Panel";
export default function Accordion() {
return (
<>
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the
1500s
when an unknown printer took a galley of type and scrambled it to make a
type specimen book. It has survived not only five centuries
>;
)
}
```
```js
// Panel.js
import { useState } from "react";
export default function Panel({title, children}) {
const [isActive, setIsActive] = useState(false);
const handleShow = () {
setIsActive(true);
}
return (
{title}
{isActive ? {children}
: Show}
)
}
```
---
### Challenge 10: Accordion Part 2 (Lifting state)
- In last challenge, we managed to create an `Accordion`, but there's one thing we could tweak for better experience.
- We want one panel expend and the other one close at same time.
- The way to implement this is to make parent component `Accordion.js` controls data.
- In this challenge, we need same components as last one, but adding more to the parent as parent component needs to control which panel is opend.
- [CodeSandbox](https://codesandbox.io/s/accordion-part-2-lifting-state-p4cptu?file=/src/Panel.js)
> **Note**
>
> **Review : Uncontrolled vs. controlled component**
>
> Usually uncontrolled component is referring to component with local state, for example : `Panel.js` from challenge 9, it controlled the `isActive` state.
>
> Controlled component on the other hand is driven by props rather then its local state, for example: `Panel.js` from challenge 10, it is fully controlled by its parent component.
>
> Generally, uncontrolled component is less flexible eventhough it requires less configuration, hence it's easier to use within parent component; Controlled components are maximally flexible, but they require the parent components to fully configure them with props.
>
> [React: Lifting state](https://beta.reactjs.org/learn/sharing-state-between-components#lifting-state-up-by-example)
Code
```js
// App.js
import Accordion from "./Accordion";
export default function App() {
return ;
}
```
```js
// Accordion.js
import { useState } from "react";
export default Accordion() {
// initialize active index
const [activeIndex, setActiveIndex] = useState(0);
return (
<>
setActiveIndex(1)}
>
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the
1500s
setActiveIndex(0)
>
when an unknown printer took a galley of type and scrambled it to make a
type specimen book. It has survived not only five centuries
>;
)
}
```
```js
// Panel.js
import { useState } from "react";
export default function Panel({ title, children, isActive, onShow }) {
const [isActive, setIsActive] = useState(false);
return (
{title}
{isActive ? {children}
: Show}
);
}
```
---
### Challenge 10-1: Synced inputs
- This challenge is from [beta reactjs org](https://beta.reactjs.org/learn/sharing-state-between-components#lifting-state-up-by-example)
Original code
```js
// App.js
import SyncedInputs from "./SyncedInputs";
export default function App() {
return (
);
}
```
```js
// SyncedInputs.js
import Input from "./Input";
export default function SyncedInputs() {
return (
<>
>
);
}
```
```js
// Input.js
import { useState } from "react";
export default Input({label}){
const [inputTxt, setInputTxt] = useState("");
const handleChange = (e) => {
setInputTxt(e.target.value);
}
return (
<>
>
)
}
```
- The code above won't sync input text as `Input.js` component is an **Uncontrolled component**, it has local state of `inputTxt` and the event `onChange`, it can only affect one component instead of both.
- Let's move local state and event from child component to parent component so that parent component can control the behaviour.
Solution
```js
// SyncedInputs.js
import { useState } from "react";
import Input from "./Input";
export default function SyncedInputs() {
const [inputTxt, setInputTxt] = useState("");
const handleChange = (e) => {
setInputTxt(e.target.value);
};
return (
<>
>
);
}
```
```js
// Input.js
export default function Input({ label, value, onChange }) {
return (
<>
{label}
>
);
}
```
---
### Challenge 10-2: Filtering a list
- This challenge is from [beta reactjs org](https://beta.reactjs.org/learn/sharing-state-between-components#lifting-state-up-by-example)
- Feature: Filter out the result that matches user input (whether is uppercase or lowercase, and it will show up while typing.)
- In this challenge, we will need:
- A file contains data - `data.js`.
- `SearchBar.js` as input field.
- `List.js` to list out all contents from `data.js`.
- `FilterableList.js` as parent component that contains two children above.
- A way(functionality) of helping us to filter item.
Original Code
```js
// data.js
export const foods = [
{
id: 0,
name: "Sushi",
description:
"Sushi is a traditional Japanese dish of prepared vinegared rice",
},
{
id: 1,
name: "Dal",
description:
"The most common way of preparing dal is in the form of a soup to which onions, tomatoes and various spices may be added",
},
{
id: 2,
name: "Pierogi",
description:
"Pierogi are filled dumplings made by wrapping unleavened dough around a savoury or sweet filling and cooking in boiling water",
},
{
id: 3,
name: "Shish kebab",
description:
"Shish kebab is a popular meal of skewered and grilled cubes of meat.",
},
{
id: 4,
name: "Dim sum",
description:
"Dim sum is a large range of small dishes that Cantonese people traditionally enjoy in restaurants for breakfast and lunch",
},
];
```
```js
// FilterTableList.js
import List from "./List";
import SearchBar from "./SearchBar";
import { foods } from "./data";
export default function FilterableList() {
return (
<>
>
);
}
```
```js
// List.js
function List({ items }) {
return (
{items.map((food) => (
{food.name}
{food.description}
))}
);
}
```
```js
// SearchBar.js
import { useState } from "react";
function SearchBar() {
const [query, setQuery] = useState("");
function handleChange(e) {
setQuery(e.target.value);
}
return (
Search:
);
}
```
Optimize
```js
// FilterTableList.js
// This is parent component which containt `SearchBar.js` and `List.js`
import SearchBar from "./SearchBar";
import List from "./List";
import { useState } from "react";
import { foods } from "./data"
export default FilterTableList() {
const [query, setQuery] = useState("")
//create a function that accept foods and query as parameters
// This function will be responsible for filtering the result that matches query text.
const filterItems = (items, query) => {
// make sure that text will be lowercase.
query = query.toLowerCase();
return items.filter((item) => item.name.split(" ").some(word => word.toLowerCase().startsWith(query)))
}
const results = filterItems(foods, query);
const handleChange = (e) => {
setQuery(e.target.value)
}
return (
)
}
```
```js
// SearchBar.js
export default SearchBar({title, query, onChange}) {
return (
)
}
```
```js
// List.js
export default List({items}) {
return (
-
{item.name}
{item.description}
{items.map((item) =>(
))}
)
}
```
- In code above, we move props from child to parent and make children as "controlled" components.
---
### Challenge 11: Fetch data (challenges related to Effects)
> **Note**
>
> Review: Two common cases in whih we don't need Effects.
>
> **1. We don't Effects to transform data for rendering.**
>
> When we update a component's state, React will [commit](https://beta.reactjs.org/learn/render-and-commit) the changes to the DOM, updating the screen, then React will run Effects, if the Effect also immidiately updates the state, it restarts the whole process from scratch.
>
> We can transform all the data ate the top level of the component without using an Effect, it will automatically re-run whenever props or state change.
>
> **2. We don't need Effects to handle user events**
> Because Effect runs in a early stage, we can't predict user's behaviour, so we can just hanlde user events in the corresponding event handlers.
---
#### Mini challenge 1: Updating state based on props or state
In this mini challenge, try to optimize code from `Original code` to see if there's a better solution.
Original Code
```js
import { useState, useEffect } from "react";
export default function Form() {
const [firstName, setFirstName] = useState("John");
const [lastName, setLastName] = useState("Smith");
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(firstName + " " + setLastName);
}, [firstName, setLastName]);
}
```
Optimized Code
```js
import { useState, useEffect } from "react";
export default function Form() {
const [firstName, setFirstName] = useState("John");
const [lastName, setLastName] = useState("Smith");
const fullName = firstName + " " + lastName;
}
```
> **Note**
>
> Avoid redundant state: If it can be calculated from the exsiting props or state, don't put it in state, calculate it during rerendering.
---
#### mini challenge 2: Caching expensive calculations
In this mini challenge, try to optimize code from `Original code` to see if there's a better solution.
Original Code
```js
import { useState, useEffect } from "react";
export default function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState("");
const [visibleTodos, setVisibleTodos] = useState([]);
useEffect(() => {
setVisibleTodos(getFilteredTodos(todos, filter));
}, [todos, filter]);
// ...
}
```
Optimized Code
```js
import { useState, useEffect } from "react";
export default function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState("");
const visibleTodos = getFilteredTodos(todos, filter);
// ...
}
```
> **Note**
>
> If we have a lot of todos, and it slow down `getFilteredTodos()` or vise versa, the `getFilteredTodos()` is already slow, but we do not want to re-render everything, in this case, we can use `useMemo()` to cache / memoize the value (`todos` || `filter`), if they haven't changed, it won't trigger re-render.
useMemo to memoize the value
```js
import { useState, useEffect } from "react";
export default function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState("");
const visibleTodos = useMemo(
() => getFilteredTodos(todos, filter),
[todos, filter]
);
// ...
}
```
> **Note**
>
> `useMemo` will remember the value of `getFilteredTodos()` during the initial render, for the next render, it will check if `todos` or `filter` are different, if the values weren't changes, `useMemo` will return the last result; if either of them have changed, `useMemo` will call the wrapped function again and store that result instead.
> **Note** **Important**
>
> The function we wrap in `useMemo` runs during rendering, this only works for [pure calculations](https://beta.reactjs.org/learn/keeping-components-pure)
>
> **Purity: Component as formulas**
>
> A pure function is a function with the following characteristics:
>
> 1. **Minds its own business.** It does not change any objects or variables that existed before it was called.
>
> 2. **Same inputs, same outputs**. Given the same inputs, a pure function should always return the same result.
---
### Challenge 12: passing props
[React Beta Challenge](https://beta.reactjs.org/learn/passing-props-to-a-component)
#### mini-challenge 1 : Extract a component
This `Gallery` component contains some very similar markup for two profiles. Extract a `Profile` component out of it to reduce the duplication. You’ll need to choose what props to pass to it.
Original Code
```js
import { getImageUrl } from './utils.js';
export default function Gallery() {
return (
Notable Scientists
Maria Skłodowska-Curie
-
Profession:
physicist and chemist
-
Awards: 4
(Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
-
Discovered:
polonium (element)
Katsuko Saruhashi
-
Profession:
geochemist
-
Awards: 2
(Miyake Prize for geochemistry, Tanaka Prize)
-
Discovered:
a method for measuring carbon dioxide in seawater
);
}
```
Solution 1
```js
// Create a js file to store all datas
// profilesData.js
export const profileData = [
{
id: "0",
name: "Maria Skłodowska-Curie",
profession: "physicist and chemist",
numOfAwards: "4",
awardsDestails:
"Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal,Matteucci Medal",
achievement: "polonium(element)",
imgId: "szV5sdG"
},
{
id: "2",
name: "Katsuko Saruhashi",
profession: "geochemist",
numOfAwards: "2",
awardsDestails: "Miyake Prize for geochemistry, Tanaka Prize",
achievement: "a method for measuring carbon dioxide in seawater",
imgId: "YfeOqp2"
}
];
```
```js
// Gallery.jsx
// datas
import { profileData } from "./profileData";
// component
import Profiles from "./Profiles"
export default function Gallery() {
return (
)
}
```
```js
// Profiles.jsx
import {getImageUrl} from "./utils.js"
export default function Profiles({ profiles }) {
return (
Notable Scientists
{profiles &&
profiles.map((profile) => (
{profile.name}
-
Profession:
{profile.profession}
-
Awards: {profile.numOfAwards}
({profile.awardsDestails})
-
Discovered:
{profile.achievement}
))}
);
}
```
Solution 2
```js
// Create a js file to store all datas
// profilesData.js
export const profileData = [
{
id: "0",
name: "Maria Skłodowska-Curie",
profession: "physicist and chemist",
numOfAwards: "4",
awardsDestails:
"Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal,Matteucci Medal",
achievement: "polonium(element)",
imgId: "szV5sdG"
},
{
id: "2",
name: "Katsuko Saruhashi",
profession: "geochemist",
numOfAwards: "2",
awardsDestails: "Miyake Prize for geochemistry, Tanaka Prize",
achievement: "a method for measuring carbon dioxide in seawater",
imgId: "YfeOqp2"
}
];
```
```js
// Gallery.jsx
// datas
import { profileData } from "./profileData";
import {getImageUrl} from "./utils.js";
export default function Gallery() {
const profileItem = profiles.map(profile => {
return (
{profile.name}
-
Profession:
{profile.profession}
-
Awards: {profile.numOfAwards}({profile.awardsDestails})
-
Discovered:
{profile.achievement}
)
})
return (
{profileItem}
)
}
```