React-Redux - rank counter table - reactjs

I am currently working on one of FCC's project, specifically to this one:
https://www.freecodecamp.com/challenges/build-a-camper-leaderboard
I was able to get it working just fine--I am able to click either recent or all-time scores and it will re-render the page accordingly.
The only thing I am missing is rendering the rank number appropriately. As of now, it is just current stack of number 1.
Here's my current code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { recentData } from '../actions/index'
import { allTimeData } from '../actions/index'
export default class TableBoard extends Component {
constructor(props){
super(props);
}
componentDidMount() {
this.props.recentData() //fetch data most recent top
}
renderData(userData){
const name = userData.username;
const recent = userData.recent;
const allTime = userData.alltime;
let rank = 1;
return(
<tr key={name}>
<td>{rank}</td>
<td>{name}</td>
<td>{recent}</td>
<td>{allTime}</td>
</tr>
)
}
getRecentData(){
console.log('recent data')
this.props.recentData()
}
getAllTimeData(){
console.log('all-time data')
this.props.allTimeData();
}
render(){
return(
<table className="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Camper Name</th>
<th
onClick={this.getRecentData.bind(this)}
>Points in 30 days
</th>
<th
onClick={this.getAllTimeData.bind(this)}
>All-time Posts
</th>
</tr>
</thead>
<tbody>
{this.props.FCCData.map(this.renderData)}
</tbody>
</table>
)
}
}
function mapStateToProps(state){
return {
FCCData: state.collectData
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ recentData, allTimeData }, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(TableBoard);
How can I add extra information into renderData function to display the rank correctly? I am assuming I need to an counter?

Pass index into map
renderData(item,index){
const name = item.username;
const recent = item.recent;
const allTime = item.alltime;
return(
<tr key={name}>
<td>{index+1}</td>
<td>{name}</td>
<td>{recent}</td>
<td>{allTime}</td>
</tr>
)
}
Table Body
<tbody>
{this.props.FCCData.map(this.renderData}
</tbody>

Related

Frontend page doesn't display unless i comment out my table making code

Here is my code. I used typescript and my database is in a .json file. My page displays fine when I don't try to display the table and disappears completely
import React, { useState } from "react";
import "./viewAvailableShifts.css";
import "bootstrap/dist/css/bootstrap.min.css";
import MockData from "./data.json";
export class ViewAvailableShifts extends React.Component {
render() {
const [data] = useState(MockData);
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>
{data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))}
</tbody>
</table>
</div>
Have you tried mapping the table rows outside of the return? Also wondering why data was in square brackets? Maybe curley braces or none at all, depending on how you return it from state? so if it's already an array just data if you need to make it an array maybe spread [...data]?
export class ViewAvailableShifts extends React.Component {
render() {
const data = useState(MockData)
const rows = data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>{rows}</tbody>
</table>
</div>
</div>
</div>
</div>
</>
)
}
}
Hooks doesn't work inside class component
import React, { useState } from "react";
import "./viewAvailableShifts.css";
import "bootstrap/dist/css/bootstrap.min.css";
import MockData from "./data.json";
export const ViewAvailableShifts = () => {
const [data] = useState(MockData);
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>
{data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))}
</tbody>
</table>
</div>
What are you trying to accomplish with useState? useState is a hook that listens for changes to data and then changes the UI accordingly. Use state returns two values though, it would be used like this...
const [data, setData]= useState(someDataOrEmptyValueButNeverActuallyEmpty)
onSomeEvent((eventOrDataOrWhatNot) => setData(eventOrDataOrWhatNot))
and then whatever in your UI that was depending on data will adjust to the new values.
So, are you ready?You can't us hooks in class components
export const ViewAvailableShifts = () => {
const [data] = useState(MockData);
‏}
Should be
export default class ViewAvailableShifts extends Component {
constructor() {
super();
this.state: {data: MockData}
}
render(){...}
}

I tried simple print function using react-to-print. Parsing error: Unexpected token, expected ","

I tried to print simple table using react-to-print. I got
Parsing error: Unexpected token, expected "," at line no 24 "const".
I am new to react.
import React, { Component } from 'react';
import ReactToPrint, { PrintContextConsumer } from 'react-to-print';
import { ComponentToPrint } from './ComponentToPrint';
export default class Form extends Component {
render() {
return (
<table>
<thead>
<th>column 1</th>
<th>column 2</th>
<th>column 3</th>
</thead>
<tbody>
<tr>
<td>data 1</td>
<td>data 2</td>
<td>data 3</td>
</tr>
</tbody>
</table>
const Example = () => {
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
return (
<div>
<ComponentToPrint ref={componentRef} />
<button onClick={handlePrint}>Print this out!</button>
</div> );
}
}
}
Sorry for necro posting, but since the answer is missing, let's fix this!
Here your Form is what should be used in place of ComponentToPrint, and of course it must be separate from your Example functional component.
That's how it is!
To explain in more details, you should have two jsx (as an example):
form.jsx
--------
import React, { Component } from 'react';
export default class Form extends Component {
render() {
return (
<table>
<thead>
<th>column 1</th>
<th>column 2</th>
<th>column 3</th>
</thead>
<tbody>
<tr>
<td>data 1</td>
<td>data 2</td>
<td>data 3</td>
</tr>
</tbody>
</table>
);
}
}
-- this is your "component to print" (i.e. it returns what will be printed out).
And also you need
example.jsx
-----------
import Form from './form';
import React, { useRef } from 'react';
import { useReactToPrint } from 'react-to-print';
const Example = () => {
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
return (
<div>
<Form ref={componentRef} />
<button onClick={handlePrint}>Print this out!</button>
</div>
);
}
-- this is your component (functional component) with "Print this out!" button which takes ref to your Form as the content for printing.
All that's left is to use your Example somewhere in the App, it will produce the table and a button, clicking the button will call printer dialogue.

Import child component to use in a html table structure

I want to import a component with a child component using specified HTML markup
I am almost there I guess, but I have some problem with the exporting. Added som more data.
usingTable.js
import React, { Component } from "react";
import tableHeader from ".components/data/tableHeader.json";
import Rows from ".components/data/rows.json";
import Table, {Row} from "./components/table.js";
class UsingTable extends Component {
render() {
return(
<>
<Table tableHeader={TableHeader} rows={Rows}>
<Row>
<td colSpan="2">A</td>
<td>B</td>
<td>C</td>
</Row>
</Table>
</>
);
}
}
export default UsingTable;
I don't know if this is the right setup. Maybe someone can give me a hand on this?
table.js
import React, { Component } from "react";
class Table3 extends Component {
render() {
const tableHeader = this.props.tableHeader.map((col,i) => (
<th>
{col}
</th>
))
const row1 = this.props.row.map((row,i) => (
<td>
{row}
</td>
))
return (
<table>
<thead>
<tr>
{tableHeader}
</tr>
</thead>
<tbody>
{Row1}
{Row}
</tbody>
</table>
)
}
}
export default Table3;
export const Row = props => {
return <tr>{props.children}</tr>
}
I want the result to be
<table>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<!-->
<tr>
<td colSpan="2">A</td>
<td>B</td>
<td>C</td>
</tr>
<!-->
</tbody>
</table>```
In your UsingTable your passing 2 props (tableHeader and rows) and 1 child (Row)
Then, in your Table3 component your mapping over tableHeader, which is a valid prop and over this.props.rows which doesn't look like its defined (row should be called rows)
If you want to use the Row child that you passed in, you need to access it using this.props.children
For example, stick {this.props.children} underneath {Row}. Hope that helps

Creating a component in react and typescript

I am trying to convert this table below from react to typescript. I want to make it universal table component where I can use for every data. This is a sample a table I created in react and its working well. In typescript, the class experts an interface which I have been finding it difficult to apply here.The table must be able to accept data from a webservice and display at any point in time. What am I supposed to add.
class Table extends Component {
render() {
const { characterData, removeCharacter } = this.props;
return (
<table className="table-bordered table-striped">
<TableHeader />
<TableBody characterData={characterData}
removeCharacter={removeCharacter}
/>
</table>
);
}
}
const TableHeader = () => {
return (
<thead>
<tr>
<th width="300">Name</th>
<th width="300">Job</th>
<th width="300">Date</th>
</tr>
</thead>
);
}
const TableBody = props => {
const rows = props.characterData.map((row, index) => {
return (
<tr key={index}>
<td >{row.name}</td>
<td >{row.job}</td>
<td >{row.date}</td>
<td><button onClick={() => props.removeCharacter(index)}>Delete</button></td>
</tr>
);
});
return <tbody>{rows}</tbody>;
}
export default Table;
You can type check your props by adding chevrons next to the Component prototype. The first argument is type checking your props and the second argument will type check your internal state.
interface TableProps {
characterData: //...however the data should be structured
removeCharacter: () => void;
}
interface TableState {
//... this is empty because you haven't defined any internal component state
}
class Table extends Component<TableProps, TableState> {
render() {
const { characterData, removeCharacter } = this.props;
return (
<table className="table-bordered table-striped">
<TableHeader />
<TableBody characterData={characterData}
removeCharacter={removeCharacter}
/>
</table>
);
}
}

Redux: using different reducers for a component

I've got a component UsersList which I'd like to reuse with two different reducers - one for listing regular users (state.users.x) and one for listing administrators (state.adminusers.x). The display is the same in both cases, but the state is in different places and different api actions apply (different endpoints with different business rules).
How can I write my component so it can use either reducer?
Write the UsersList component as normal, but do not connect it to redux.
For example:
import React, { Component } from 'react';
import { Table } from 'react-bootstrap';
import UserInviteRow from 'jsx/components/Lib/Users/UserInviteRow';
export class UsersList extends Component {
render() {
const { inviteUserToOrg } = this.props;
return (
<Table bordered hover>
<thead>
<tr>
<th className="width-200">First Name</th>
<th className="width-250">Last Name</th>
<th>Email</th>
<th className="width-150">Last Login</th>
<th className="width-100"> </th>
</tr>
</thead>
<tbody>
<UserInviteRow invitefxn={ inviteUserToOrg }/>
{ this.renderRows() }
</tbody>
</Table>
);
}
renderRows() {
const { usersList } = this.props;
if( ! usersList.length ) {
return (
<tr>
<td colSpan="5">
<em>No users exist for this non-profit</em>
</td>
</tr>
);
}
return usersList.map( (user) => {
return (
<tr key={user.key}>
<td>{user.firstName}</td>
<td>{user.lastName}</td>
<td>{user.correspondenceEmailAddress}</td>
<td>{ (user.lastSeen) ? formatTime(user.lastSeen) : '' }</td>
<td className="text-center">
{ this.renderRemoveButton( user ) }
</td>
</tr>
);
});
}
renderRemoveButton(user) {
const { currentUser } = this.props;
if( currentUser.key === user.key ) {
// users cannot remove themselves
return null;
}
return (
<a className="text-danger" onClick={ () => { this.removeUser(user) } }>
<em className="fa fa-times" />
</a>
);
}
removeUser( user ) {
this.props.removeUserFromOrg(user.key);
}
}
export default UsersList;
Make sure both your reducers implement the action functions you use, in this case inviteUserToOrg and removeUserFromOrg.
Create new container components connected to each reducer
For example:
import { connect } from 'react-redux';
import {
inviteUserToOrg,
removeUserFromOrg
} as actions from 'jsx/redux/modules/nonadminUsers';
import UsersList from 'jsx/components/Lib/Users/UsersList';
var NonadminUserList = connect(
state => {
return {
usersList: state.users.usersList,
};
},
actions
)(UsersList);
export default NonadminUserList;
and
import { connect } from 'react-redux';
import {
inviteUserToOrg,
removeUserFromOrg
} as actions from 'jsx/redux/modules/adminUsers';
import UsersList from 'jsx/components/Lib/Users/UsersList';
var AdminUserList = connect(
state => {
return {
usersList: state.adminusers.usersList,
};
},
actions
)(UsersList);
export default AdminUserList;
Now changes to your presentation component, UsersList, will affect both container components and each container component can reference it's own reducer state and actions.

Resources