CSS style
boostrap is popular css library.
npm install bootstrap
Browse to the project folder. When first generated by bite, there is an App.css and an Index.css. They the CSS for the App component and the CSS for the global, imported by App.tsx and main.tsx separately.
Remove the content of the App.css and index.css, leaving them empty for now.
Go the main.tsx, replace the "import './index.css'" with
import 'bootstrap/dist/css/bootstrap.css'
So now it is using the boostrap's css file. The helloworld page / whatever page will be updated now with the new font, location, etc.
A dynamic list group component
It's good to create a components folder in the src folder, so it doesn't make the main src folder to messy.
Under the components folder, create a new component using PascalNaming convention "ListGroup.tsx"
function ListGroup(){
return <h1>list group</h1>;
}
export default ListGroup;
For now the ListGroup.tsx simply returns an h1 element.
Go to the App.tsx under src folder. Import the ListGroup component and use the ListGroup in the App component.
import ListGroup from './components/ListGroup';
function App() {
return <div><ListGroup/></div>; //use the Message component like a html element
}
export default App;
Now refresh the web page, it should show the list group message.
To apply a boostrap CSS style to the ListGroup component, firstly find the html element for List Group on getbootstrap.com
Go the Docs and Components, there are plenty of examples of how to use each component with the boostrap style. Lets look at the List Group, it has something like
<ul class="list-group">
<li class="list-group-item">An item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>
This is how a list group is defined in HTML and how the list-group style is refered to. Copy the List Group's html code snippet to ListGroup.tsx.
function ListGroup(){
return (
<ul className="list-group">
<li className="list-group-item">An item</li>
<li className="list-group-item">A second item</li>
<li className="list-group-item">A third item</li>
<li className="list-group-item">A fourth item</li>
<li className="list-group-item">And a fifth one</li>
</ul>
);
}
export default ListGroup;
Some changes are needed here. Firstly a pair of () is used for enclosing the multi-line element. Secondly, the "class" is changed to "className" because class is a reserved word in typescript for defining class.
Done. refersh the page to see a group of list item.
Note that within a component, it CAN NOT return multiple HTML elements in parallel.
return (<h1>a</h1> <h1>b</h1>)
The above will fail, but you can wrap both in a <div> for example to make it one element
return <div><h1>a</h1> <h1>b</h1></div>
If you don't like extra div in the code, you may use the Fragment in react. The Fragment basically is the virtual wrapper of HTML elements. After compiled, there wont be a fragment element in the code.
import {Fragment} from "react";
function ListGroup(){
return (
<Fragment>
<h1>good day</h1>
<ul className="list-group">
<li className="list-group-item">An item</li>
<li className="list-group-item">A second item</li>
<li className="list-group-item">A third item</li>
<li className="list-group-item">A fourth item</li>
<li className="list-group-item">And a fifth one</li>
</ul>
</Fragment>
);
}
export default ListGroup;
A more handy way is just using empty brackets, then the compiler knows it is Fragment
function ListGroup(){
return (
<>
<h1>good day</h1>
<ul className="list-group">
<li className="list-group-item">An item</li>
<li className="list-group-item">A second item</li>
<li className="list-group-item">A third item</li>
<li className="list-group-item">A fourth item</li>
<li className="list-group-item">And a fifth one</li>
</ul>
</>
);
}
export default ListGroup;
You don't want to manually type in every list item, so it needs to be programatically populated in a loop. But you can't just write a loop to repeat the <li> item within <ul>, the below is wrong syntax. The mix of html and typescript is not supported.
<ul className="list-group">
for (let i=0;i<10;i++){
<li className="list-group-item">{i}</li>
}
</ul>
The way to achieve it is using the "map" function in typescript, which maps every item in the array to an HTML li item. Note braces {} are required for embedding the code, and the item value. The {} are nested. The map function helps to create another array of html elements based on the the original array. A for loop does not yield items as an array, so it won't work.
function ListGroup(){
let cities = ['brisbane', 'sydney', 'melbourne'];
return (
<>
<h1>good day</h1>
<ul className="list-group">
{cities.map(city => <li className="list-group-item">{city}</li>)}
</ul>
</>
);
}
export default ListGroup;
However, you can loop through items outside of the return statement to prepare a list of HTML elements and use the items list within the return statement.
function ListGroup(){
let cities = ['brisbane', 'sydney', 'melbourne', 'ny'];
let items:any[] = [];
cities.forEach(city=>{
items.push(<li className="list-group-item">{city}</li>)
})
return (
<>
<h1>good day</h1>
<ul className="list-group">{items}</ul>
</>
);
}
export default ListGroup;
Another way to loop through is
for (var c of cities){
items.push(<li className="list-group-item">{c}</li>);
}
Here it uses the forEach / for loop method to push each <li> item to another array with 'any' type. the 'any[]' tells the editor to not complain about data type otherwise you may get a red curley error. As the items list is already holding the <li> elements, the <ul> list group can simply refer to it {items}.
If condition
You may want to add some if conditions to the component, e.g. if the list of cities is empty, then show a message saying "no city in the list".
{cities.length===0 ? <h1>no city in the list</h1> : null}
Another showing-off but not readable trick is using the &&. In javascript, TRUE && some value returns some value. False && some value returns false.
{cities.length===0 && <h1>no city in the list</h1>}
onClick event
Add an onClick event handler which passes the optional 'event' parameter, and log the event. In the html element, compiler know the event is a React.MouseEvent, but if you move the onClick handler outside, it won't know.
function ListGroup(){
let cities = ['brisbane', 'sydney', 'melbourne'];
return (
<>
<h1>good day</h1>
<ul className="list-group">
{cities.map(city =>
<li
className="list-group-item"
onClick={(event)=>console.log(event)}
>
{city}
</li>
)}
</ul>
</>
);
}
export default ListGroup;
Here is the example of using onClick handler outside of the html block
import {MouseEvent} from "react";
function ListGroup(){
let cities = ['brisbane', 'sydney', 'melbourne'];
let clickHandle = (event:MouseEvent)=> console.log(event);
return (
<>
<h1>good day</h1>
<ul className="list-group">
{cities.map(city =>
<li
className="list-group-item"
onClick={clickHandle}
>
{city}
</li>
)}
</ul>
</>
);
}
export default ListGroup;