0% found this document useful (0 votes)
6 views10 pages

Exe2 ENG

This document outlines instructions for a laboratory task in modern frontend web application development, requiring participants to write code that passes specific tests within a 120-minute timeframe. It details the creation of various React components, including a counter and a letter counter, while adhering to strict guidelines regarding file modifications and submission formats. Additionally, it emphasizes the importance of using a reducer for state management and provides a comprehensive overview of the tasks, including state structure, handling user input, and managing API calls.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views10 pages

Exe2 ENG

This document outlines instructions for a laboratory task in modern frontend web application development, requiring participants to write code that passes specific tests within a 120-minute timeframe. It details the creation of various React components, including a counter and a letter counter, while adhering to strict guidelines regarding file modifications and submission formats. Additionally, it emphasizes the importance of using a reducer for state management and provides a comprehensive overview of the tasks, including state structure, handling user input, and managing API calls.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

Modern frontend web application development - laboratory

Filip Rynkiewicz Marcin Daszuta


e-mail [email protected] e-mail [email protected]
26th January 2025

Instructions
You will have 120 minutes to write code that must pass all the provided tests.

Do not create any new files in this project, and do not


modify anything outside the files in src/components.
Any changes in other files may lead to unsolvable errors.
All you need to do is install npm and Node.js, unpack the archive, and set up the
entire environment from the archive (using the command npm i).

The HTML tags (or JSX.IntrinsicElements), file names, and any other explicitly
specified information must match the instructions exactly; otherwise, the tests will
not be accepted.

Each test that passes equals 1 point. The point-to-grade mapping is listed in the
task description on MS Teams.

Submit your solution (entire project) as a zipped archive. Any other archive
format will not be checked.

Please remove the node modules folder from your submission.

1
Any attempt at plagiarism will result in a grade of 2, with no
option to resubmit tasks.

2
Running Tests
To run tests, use the command npm test in the terminal in the main project folder. This command
will run continuously, and any changes in the project files will automatically trigger the tests.

Figure 1: All tests passed

Figure 2: No tests passed

3
Figure 3: Some tests passed

Tasks
Task 1
In file Counter.jsx create new component called Counter. Component should consist of 3 buttons
and one h1 tag.
ˆ One button will increase the counter, MUST display string Increase,

ˆ One button will decrease the counter, MUST display string Decrease,

ˆ One button will reset the counter, MUST display string Reset,

ˆ h1 MUST display current number stored in state.count ( state of the reducer )

You must ensure that there will be no possibility that counter will be lower than 0, cannot be
negative number.

To manage state changes in Counter you have to use a reducer hook. Create a function named
reducer which will take two arguments ( must be named like this) :
ˆ state, which will contain the count

ˆ action, which contain the type

based on value of action.type You have to implement component behavior.

ˆ if user will click the Increase button the state of counter will increment by 1,

– call reducer dispatch function with type value INCREASE


ˆ decrement by one if the user will click to the Decrement button,

– call reducer dispatch function with type value DECREASE

ˆ and set to 0 if the Reset button will be clicked.

– call reducer dispatch function with type value RESET

as an initial state of reducer use:


1 const initialState = { count : 0 };

Component Counter, initialState and reducer function MUST be EXPORTED

4
Task 2
In this task the scheme of LetterCounter component, in LetterCounter.jsx is provided as fallows (
do not modify provided code )
1 <>
2 <h1 > Complex Letter Counter </ h1 >
3 <div >
4 < label >
5 Text :
6 < input type =" text " value ={ state . text } onChange ={ h a n d l e T e x t C h a n g e } / >
7 </ label >
8 </ div >
9 { state . letters . map (( letter , index ) = > (
10 < div key ={ index } >
11 < label >
12 Letter { index + 1}:
13 < input type =" text " value ={ letter } onChange ={ h a n d l e L e t t e r C h a n g e ( index ) } / >
14 </ label >
15 </ div >
16 ))}
17 < button onClick ={ ad dLetter Field } > Add Letter </ button >
18 < button onClick ={ r e m o v e L e t t e r F i e l d } disabled ={ state . letters . length <= 1} >
19 Remove Letter
20 </ button >
21 < button onClick ={ c o u n t O c c u r r e n c e s } > Count </ button >
22 { results }
23 </ >

Application Structure
The application has the following primary components:

ˆ State: The application maintains three pieces of state:

– text: A string representing the text that the user inputs.


– letters: An array of letters for which the user wants to track occurrences in the text.
– counts: An array of numbers representing how many times each letter appears in the
text.
1 const initialState = {
2 text : ’’,
3 letters : [ ’ ’] ,
4 counts : [] ,
5 };

ˆ Reducer: A reducer function ( need to be named like that) is used to handle different actions,
such as setting text, adding/removing letters, and counting occurrences.
ˆ User Interface: The UI includes:

– An input field for the user to type in the text they want to analyze.
– Dynamic input fields for each letter the user wants to track.

5
– Buttons to add or remove letter input fields.
– A button to trigger the counting of letter occurrences.
– A section that displays the results showing how many times each letter appears in the
text.

Setting Up the State with useReducer


ˆ Reducer: Implement a reducer function which will take two arguments

– state, which is same type as initialState


– action, which contain the
* index
* payload

based on value of action.type You have to implement component behavior. that handles
different actions:

– SET TEXT: Updates the text property when the user types in the text input field.
* send payload with value of state.text
– SET LETTER: Updates the letters array when the user modifies a specific letter input
field.
* send payload with value of letter
* send index , same as in handleLetterChange
– ADD LETTER: Adds a new empty letter input field to the letters array.
– REMOVE LETTER: Removes the last letter input field from the letters array, but ensure
that at least one letter input field remains.
– SET COUNTS: Updates the counts array, which will hold the number of occurrences of each
letter in the text.
* send payload with value of counts
* send index , same as in handleLetterChange

Handling User Input


ˆ Text Input: Create an input field for the user to type in the text they want to analyze. As
the user types, dispatch the SET TEXT action to update the text in the state.
ˆ Letter Inputs: Dynamically generate input fields for each letter in the letters array. Each
input field should correspond to one letter the user wants to track. When a user changes a
letter in an input field, dispatch the SET LETTER action to update the specific letter in the
letters array.

ˆ Add/Remove Letter Fields: Provide buttons to allow the user to add or remove letter
input fields:

6
– When the ”Add Letter” button is clicked, dispatch the ADD LETTER action to add a new
empty letter field. (add new element to letters field of state)
– When the ”Remove Letter” button is clicked, dispatch the REMOVE LETTER action to
remove the last letter field (remove last element from letters field of state), but ensure
that at least one letter input field remains.

Counting Letter Occurrences


ˆ Count Occurrences: Implement a function called countOccurrences that counts how many
times each letter in the letters array appears in the text. The counting should be case-
insensitive.
– For each letter:
* If the letter is empty or contains more than one character, set its count to 0 (ignore
invalid letters).
* Otherwise, count number of times the letter appears in the text.
– Dispatch the SET COUNTS action to update the counts array with the new letter counts.

Displaying the Results


– Render the Results: Use useMemo to memoize the results of the letter counts, so that
the UI does not re-render unnecessarily. For each letter in the letters array, display a
paragraph element that shows the letter and its corresponding count from the counts
array.

Component LetterCounter, initialState and reducer function MUST be EXPORTED

Task 3
In this task the scheme of PokemonList and MemoizedPokemonElem component, in Pokemon-
List.jsx and PokemonElem.jsx is provided in files.

MemoizedPokemonElem
MemoizedPokemonElem component must be responsible for displayin name of the pokemon
( in a p HTML tag, and it’s picture ( in img HTML tag ) based on the parameters that are
send to this component as properties. Component must be wrapped in a li HTML tag, and
using the React.memo functionality

7
PokemonList
PokemonList component must be responsible for displaying a list of MemoizedPokemonElem
componenets. It must wrap the MemoizedPokemonElem components in a ul HTML tag.
This component is also responsible for fetchin information from PokeApi using this fetch string:
1 https :// pokeapi . co / api / v2 / pokemon ? limit = pokeNumber

Remember how to pass a variable to a string! Do not copy past this code, as it
will not work.
Where the pokeNumber is a property of component. In example:
1 < PokemonList pokeNumber ={10}/ >
2 < PokemonList pokeNumber ={14}/ >
3 < PokemonList pokeNumber ={1022}/ >
4 < PokemonList / >

First will call for fetching 10 pokemons, second will fetch 14, third 1022, and last ( where this
parameter is not set) will fetch 10 pokemons.

If the fetch call is waiting, You have to display information


1 Loading ...

inside the p HTML tag.


If the fetch will fail You have to throw an Error with a string:
1 Network response was not ok

5.1 Create State Management with useReducer

1 const initialState = {
2 pokemonList : [] ,
3 loading : true ,
4 error : null ,
5 filter : ’’,
6 };

– Create an initial state object that holds:


* pokemonList: An array to store the list of Pokémon.
* loading: A boolean to track the loading state of the API request.
* error: A string to store error messages in case of a request failure.
* filter: A string to hold the current filter text entered by the user for searching
Pokémon by name.
– Define a reducer function to manage state transitions. This function should handle:
* FETCH SUCCESS: Updates pokemonList with the fetched Pokémon and sets loading
to false.
* FETCH ERROR: Sets loading to false and stores the error message in error.
* SET FILTER: Updates the filter state with the search text entered by the user.

8
5.2 Set Up the useReducer Hook
– Inside your main component (e.g., PokemonList), use the useReducer hook to manage
the state of your application.
– Pass the reducer function and the initial state to the useReducer hook.

5.3 Create the API Call to Fetch Pokémon


– Use the useEffect hook to trigger the API call when the component mounts or when
pokeNumber changes.
– Inside useEffect, define an asynchronous function called fetchPokemon that:
* Fetches a list of Pokémon names from the PokeAPI.
* After receiving the list of names, sends individual requests to fetch details about each
Pokémon (e.g., their stats, images, etc.).
* On successful fetching, dispatch an action FETCH SUCCESS to update the state with
the detailed Pokémon data.
* If an error occurs during the fetching process, dispatch an action FETCH ERROR to
update the error state.

5.4 Filter Pokémon Based on Search Text


– Create an input field where the user can type to filter Pokémon by name.
– Add an onChange event handler to this input that dispatches an action SET FILTER to
update the filter state with the user’s input text.

5.5 Memoize the Filtered List of Pokémon


– Use the useMemo hook to create a filtered list of Pokémon based on the current value of
filter.
– Filter the pokemonList by comparing each Pokémon’s name to the current filter string
(case insensitive).
– Only recalculate the filtered list when either the pokemonList or filter changes.

5.6 Memoize the Rendering of Pokémon Elements


– Use useMemo again to generate the JSX elements for the filtered Pokémon list.
– Each Pokémon element should be passed to a memoized child component (e.g., MemoizedPokemonElem)
for better performance.
– Ensure each list item has a unique key prop (use the Pokémon’s id).

9
5.7 Handle Loading and Error States
– Before rendering the Pokémon list, check if the data is still loading or if an error occurred:
* If loading is true, display a "Loading..." message.
* If there is an error (error state is not null), display the error message.
– If neither condition is true, render the filtered Pokémon list.

Summary of Reducer Actions and State Transitions

6.1 FETCH SUCCESS


– type: FETCH SUCCESS
– payload: An array of detailed Pokémon data (e.g., name, image, stats).
– Updates the following state:
* pokemonList: The fetched Pokémon data.
* loading: false (indicates the fetch is complete).

6.2 FETCH ERROR


– type: FETCH ERROR
– payload: The error message as a string.
– Updates the following state:
* error: Contains the error message from the API.
* loading: false (indicates an error occurred).

6.3 SET FILTER


– type: SET FILTER
– payload: The current filter text (string) entered by the user.
– Updates the following state:
* filter: The filter string used for searching Pokémon by name.

10

You might also like