Creating Multiple Buttons Using React Classes - javascript

I'm currently trying to return multiple buttons from a class using Reactjs. Currently I can get all the buttons to return but the onClick function will only work on the last button to be displayed. If anyone can help its greatly appreciated. Here are the important lines of code.
let GroupCollection2 = db.collection('groups');
GroupCollection2.get()
.then(snapshot => {
snapshot.forEach(doc => {
if(doc.get('ModuleCode') === document.getElementById("groupSearch").value)
{
document.getElementById("groupDisplayError").innerHTML = "";
if(found === false){
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
}
found = true;
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
});
if(found === false){
document.getElementById("groupDisplayError").innerHTML = "No Results.";
}
})
.catch(err => {
console.log('Error getting documents', err);
});
and
class Button extends React.Component{
joinGroup(command){
alert(command);
}
render(){
return(<button onClick={this.joinGroup.bind(this, this.props.command ) }>Join Group</button>);
}
}
The entire code is here:
import React from "react";
import ReactDOM from 'react-dom';
import { compose } from "redux";
import { connect } from "react-redux";
import { signout } from "../store/actions/auth";
import requireAuth from "./hoc/requireAuth";
import firebase from "../services/firebase.js";
import Calendar from "./Planner.js"
//<Calendar />
var db = firebase.firestore();
const Main = ({ signout }) => {
return (
<div id="homePage" className="container">
<div className="row">
<div class="col s6" id="createPage">
<form id="createGroup">
<i className="large material-icons prefix search-icon">group_add</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<input type="text" id="cgroupName" name="groupName"/>
<label htmlFor="cgroupName">Group Name</label>
</div>
</div>
<div className="row">
<div className="input-field col s12 vert-align">
<input type="text" id="cgroupModuleCode" name="moduleCode"/>
<label htmlFor="cgroupModuleCode">Module Code</label>
</div>
</div>
<div className="row">
<input type="button" value="Create Group" onClick={ ()=> createGroup()}/>
</div>
<p id="groupCreateError"></p>
</div>
</div>
</form>
</div>
<div className="col s6">
{/*<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-database.js"></script>*/}
{/* Renders the search bar */}
<i className="large material-icons prefix search-icon">group</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<i className="material-icons prefix search-icon">search</i>
<input type= "text" id ="groupSearch" name="searchGroup"/>
<label htmlFor="groupSearch">Search For A Group</label>
<a className="waves-effect waves-teal btn-flat search-btn" onClick={ ()=> searchGroups()}>Search</a>
</div>
</div>
</div>
</div>
{/* Display any searched groups here */}
<div class="row" id="groupDisplay">
<p id="groupDisplayError"></p>
<table id="groupDisplayTable">
</table>
</div>
</div>
</div>
<button onClick={ () => profile()} hidden>Profile</button>
<button className="btn-switch" onClick={() => signout()}>Log Out</button>
</div>
);
};
function mapStateToProps(state) {
return {
auth: state.firebaseReducer.auth
};
}
function mapDispatchToProps(dispatch) {
return {
signout: () => dispatch(signout())
};
}
function profile(){
}
function logOut(){
document.getElementById("navbar").style.display = "none";
signout();
}
function searchGroups(){
if(document.getElementById("groupSearch").value === ""){
document.getElementById("groupDisplayError").innerHTML = "Please enter a value and try again.";
}
else{
var found = false;
var count = 0;
let GroupCollection = db.collection('groups').doc(document.getElementById("groupSearch").value);
GroupCollection.get()
.then(doc => {
if (doc.exists) {
found = true;
document.getElementById("groupDisplayError").innerHTML = "";
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id}/>, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
})
.catch(err => {
document.getElementById("groupDisplayError").innerHTML = "Error getting document: "+err;
});
let GroupCollection2 = db.collection('groups');
GroupCollection2.get()
.then(snapshot => {
snapshot.forEach(doc => {
if(doc.get('ModuleCode') === document.getElementById("groupSearch").value)
{
document.getElementById("groupDisplayError").innerHTML = "";
if(found === false){
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
}
found = true;
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
});
if(found === false){
document.getElementById("groupDisplayError").innerHTML = "No Results.";
}
})
.catch(err => {
console.log('Error getting documents', err);
});
}
}
function createGroup(){
let GroupCollection = db.collection('groups').doc(document.getElementById("cgroupName").value);
GroupCollection.get()
.then(doc => {
if (!doc.exists) {
document.getElementById("groupCreateError").innerHTML = "Group created sucessfully.";
const GroupCollection2 = db.collection('groups');
GroupCollection2.doc(document.getElementById("cgroupName").value).set({
ModuleCode:document.getElementById("cgroupModuleCode").value,
Timetable: "",
User0: firebase.auth().currentUser.email,
User1: "",
User2: "",
User3: "",
User4: "",
User5: "",
User6: "",
User7: "",
User8: "",
User9: "",
})
} else {
document.getElementById("groupCreateError").innerHTML = "Group Name Already Exists.";
}
})
.catch(err => {
document.getElementById("groupCreateError").innerHTML = "Error getting document: "+err;
});
}
class Button extends React.Component{
joinGroup(command){
alert(command);
}
render(){
return(<button onClick={this.joinGroup.bind(this, this.props.command ) }>Join Group</button>);
}
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
requireAuth
)(Main);

You may have to make sure each button as a unique key. In this case, using the doc.id may work. So, you would want to add a key prop as below:
ReactDOM.render(<Button command={doc.id} key={doc.id} />,
document.getElementsByClassName('groupDisplayTableButton')[count]);
If there's any chance that you will have multiple of the same doc.id, you could modify the key to include the count to ensure each button has a unique key. i.e key={doc.id + count}

I don't think you are binding the joinGroup function properly. Try replacing your Button class with the following functional component:
const Button = ({ command }) => {
const joinGroup = _command => alert(_command);
return (
<button type="button" key={command} onClick={() => joinGroup(command)}>
Join Group
</button>
);
};

Unfortunately, I don't have a solution. That said, I definitely think this line is the problem: ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);.
Do not use ReactDOM.render inside the app, render the buttons to their parent, in this case, the table. You can't exactly do that since the table doesn't exist because you are manually adding elements to the DOM.
In the process of trying to figure out what is going on, I ended up refactoring half your code. Thought I'd share it in case it helps at some point.
Here is a sandbox to show that the click handler works with multiple table buttons.
I removed the search function and mocked out firebase.
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
return <Main />;
}
const Main = () => {
// fake firebase mock
const [firebaseMock, setFirebaseMock] = useState("");
// input fields
const [groupName, setGroupName] = useState("");
const [moduleCode, setModuleCode] = useState("");
// error messages
const [errorMessage, setErrorMessage] = useState("");
const createGroup = (_groupName, _moduleCode) => {
// ensure user submist a group name and a module code
if (!_groupName || !_moduleCode) {
setErrorMessage("You must provide a group name and a module code.");
return;
}
// if group already exists with the same name, create an error message
if (Object.keys(firebaseMock).includes(_groupName)) {
setErrorMessage("Group Name Already Exists.");
return;
}
setFirebaseMock({
...firebaseMock,
[_groupName]: { ModuleCode: _moduleCode }
});
// clear inputs
setGroupName("");
setModuleCode("");
};
return (
<div id="homePage" className="container">
<div className="row">
<div class="col s6" id="createPage">
<form id="createGroup">
<i className="large material-icons prefix search-icon">group_add</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<input
type="text"
id="cgroupName"
name="groupName"
value={groupName}
onChange={e => setGroupName(e.target.value)}
/>
<label htmlFor="cgroupName">Group Name</label>
</div>
</div>
<div className="row">
<div className="input-field col s12 vert-align">
<input
type="text"
id="cgroupModuleCode"
name="moduleCode"
value={moduleCode}
onChange={e => setModuleCode(e.target.value)}
/>
<label htmlFor="cgroupModuleCode">Module Code</label>
</div>
</div>
<div className="row">
<input
type="button"
value="Create Group"
onClick={() => createGroup(groupName, moduleCode)}
/>
</div>
<p id="groupCreateError">{errorMessage}</p>
</div>
</div>
</form>
</div>
<div class="row" id="groupDisplay">
{!!Object.keys(firebaseMock).length && (
<table id="groupDisplayTable">
<thead>
<tr id="groupDisplayTableHeader">
<th>Group Name</th>
<th>Module Code</th>
<th>Join Or View Group</th>
</tr>
</thead>
<tbody>
{Object.keys(firebaseMock).map(groupId => (
<tr>
<td>{groupId}</td>
<td>{firebaseMock[groupId].ModuleCode}</td>
<td class="groupDisplayTableButton">
<Button command={groupId} />
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</div>
);
};
const Button = ({ command }) => {
const joinGroup = _command => console.log(_command);
return (
<button type="button" key={command} onClick={() => joinGroup(command)}>
Join Group
</button>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The only difference here is that none of my functions contains HTML, they just manipulate state. In the future, a simple way to think in react is to always make sure that HTML code only lives in the render function. That way everything else only manipulates data and state. This decoupling of the soul of an app (data) from the body of app (HTML)lets the HTML 'react' to changes in state, which is the whole point of the framework.

Related

radio button input controlling in react js

I have a form which has both boolean and string data to be shown in. I was able to control text fields with the help of state, but boolean fields are controlled with the help of enable and disable radio button. Was not able to control the boolean fields as there are many to be done. Is there any way that I can get the inputs for the fields?
import React, { useState } from 'react';
import moment from 'moment';
export const ConfigurationPage = (props) => {
const { t } = useTranslation();
const [configResp, setConfigResp] = useState({});
const [configSet,setConfigSet]=useState(null);
const [checked,isChecked]=useState(false);
React.useEffect(() => {
fetchConfig();
}, []);
React.useEffect(() => {
setInputConfig();
}, [configResp]);
const setInputConfig=()=>{
setConfigSet(configResp);
}
const fetchConfig = async() => {
try {
const resp = await APIEndpoint.get(`customer/app/config`);
if(resp.success){
const {result}=resp;
setConfigResp(result);
}
}
catch (resp) {
console.log(resp.msg)
}
}
const onChange = (e) => {
setConfigSet({[e.target.name]: e.target.value})
}
const getDate=()=>{
return moment().subtract(1, 'days').format('YYYY-MM-DD')+"T18:30:00.000Z"
}
return (
<div className="overlay" role="dialog">
<div className="dialog sm-scrollbar">
<div className="dialog__content">
<h2 className="dialog__title subheading-text-medium fontMedium">{preCompile.title}</h2>
<hr />
<div class="dialog__body_container flexRow justifyContentSpaceBetween flexWrap">
<div class="flexCol justifyContentSpaceEvenly ">
<div class=" dialog__container_item input-container">
<div class="dialog__description">
<label class="req_conf">Account Alias</label>
<input
id={''}
name="accountAlias"
onChange={(e)=>onChange(e)}
value={configSet?configSet.accountAlias:""}
type={'text'}
className='edit-input'
/>
</div>
</div>
</div>
<div class="flexCol justifyContentSpaceEvenly ">
<div class=" dialog__container_item input-container">
<div class="dialog__description">
<label class="req_conf">mSwipe</label>
<>
<div className={`dialog__description__radio`}>
<label>Enable</label>
{configSet.mswipeEnabled?<input id="" type="radio"
name="mswipeEnabled"
value={configSet.mswipeEnabled}
checked={configSet?.mswipeEnabled}
onChange={(e)=>onChange(e)} />:<input id="" type="radio"
name="mswipeEnabled"
value={!configSet.mswipeEnabled}
checked={!configSet?.mswipeEnabled}
onChange={(e)=>onChange(e)} />}
<label>Disable</label>
<input id="" type="radio"
name="mswipeEnabled"
value={configSet?configSet.mswipeEnabled:checked}
checked={configSet?.mswipeEnabled}
onChange={(e)=>onChange(e)} />
</div>
</>
</div>
</div>
</div>
</div>
<div className="dialog__footer flexCol alignItemsCenter">
<button className="done-button" onClick={props.onSubmit}>{props.title === 'Edit Item' ? 'Update' : 'Save'}</button>
</div>
</div>
</div>
);
}
Here I am trying to change values of mswipe fields which is a boolean with enable and disabled. Is there any way to do this?

is this a result of firestore latency or normal behavior

I have a form I am using to allow users to add comments to my site. The form has an input field, a textarea field, and a button. When the button is clicked it runs my addComment() function which adds the name, comment, and timestamp to my firestore collection as a new doc.
It seems like after I click the button to add a comment I have to wait a few seconds before I can post another one. If I try to add a new comment too quickly then request doesn't get sent to my firestore collection, but if I wait a few seconds everything works as expected.
I am curious if this is normal behavior? How can I set it up so users can always post comments without having to wait a few seconds? Can someone explain to me what is happening?
Thanks
Update:
I have been doing some debugging, and I have noticed that both of the functions getVisitorCount() and getUserComments() from the first useEffect run every time I type something into the name or comment input boxes. I have attached screenshots to showcase what is happening.
On the first initial load of the app:
After typing something in the name input box:
Finally, typing something into the comment box as well:
This is not the desired behavior I want these two functions should not be running when I am typing something into either text field. The getUserComments function should only run on the initial render of the app, and whenever the add comment button is clicked.
Could this be what is causing the problems I am experiencing?
import React, { useState, useEffect } from "react";
import { NavBar, Footer, Home, About } from "./imports";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { db } from "./firebase-config";
import {
collection,
getDocs,
doc,
updateDoc,
addDoc,
Timestamp,
} from "firebase/firestore";
export default function App() {
const [formData, setFormdata] = useState([]);
const [numberOfVisitors, setnumberOfVistors] = useState([]);
const [userComments, setUserComments] = useState([]);
const portfolioStatsRef = collection(db, "portfolio-stats");
const userCommentsRef = collection(db, "user-comments");
const currentNumberOfVisitors = numberOfVisitors.map((visitors) => {
return (
<h2 className="p-3 mb-0 bg-dark bg-gradient text-white" key={visitors.id}>
Number of vistors: {visitors.visitor_count}
</h2>
);
});
const listOfUserComments = userComments.map((comment) => {
return (
<li className="list-group-item" key={comment.id}>
<div className="d-flex w-100 justify-content-center">
<h5 className="mb-1">{comment.name}</h5>
<small>{comment.date.toDate().toString()}</small>
</div>
<p className="d-flex justify-content-center mb-1">{comment.comment}</p>
</li>
);
});
useEffect(() => {
const getVisitorCount = async () => {
const dataFromPortfolioStatsCollection = await getDocs(portfolioStatsRef);
setnumberOfVistors(
dataFromPortfolioStatsCollection.docs.map((doc) => {
return { ...doc.data(), id: doc.id };
})
);
};
const getUserComments = async () => {
const dataFromUserCommentsCollection = await getDocs(userCommentsRef);
setUserComments(
dataFromUserCommentsCollection.docs.map((doc) => {
return { ...doc.data(), id: doc.id };
})
);
};
getVisitorCount();
getUserComments();
}, [numberOfVisitors, portfolioStatsRef, userCommentsRef]);
useEffect(() => {
const updateVisitorCount = async () => {
const portfolioStatsDoc = doc(
db,
"portfolio-stats",
numberOfVisitors[0].id
);
const updatedFields = {
visitor_count: numberOfVisitors[0].visitor_count + 1,
};
await updateDoc(portfolioStatsDoc, updatedFields);
};
if (!numberOfVisitors.length) return;
let sessionKey = sessionStorage.getItem("sessionKey");
if (sessionKey === null) {
sessionStorage.setItem("sessionKey", "randomString");
updateVisitorCount();
}
}, [numberOfVisitors]);
const handleFormData = (event) => {
setFormdata((prevFormData) => {
return {
...prevFormData,
[event.target.name]: event.target.value,
};
});
};
const addComment = async () => {
const newComment = {
name: formData.name,
comment: formData.comment,
date: Timestamp.now(),
};
await addDoc(userCommentsRef, newComment);
};
return (
<>
<div className="d-flex flex-column overflow-hidden min-vh-100 vh-100">
<NavBar />
<div className="row">
<div className="col text-center">
{numberOfVisitors.length === 0 && (
<h2 className="p-3 mb-0 bg-dark bg-gradient text-danger">
Sorry, the Firestore free tier quota has been met for today.
Please come back tomorrow to see portfilio stats.
</h2>
)}
{currentNumberOfVisitors}
</div>
</div>
<div className="bg-image">
<div className="postion-relative">
<main className="flex-grow-1">
<div className="container-fluid p-0">
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
<div className="row">
<div className="center-items col">
<h4 className="">Comments</h4>
</div>
</div>
<div className="row">
<div className="center-items col">
<div className="comments-container">
{userComments.length === 0 && (
<h4 className="text-danger bg-dark m-1 p-1">
Sorry, the Firestore free tier quota has been met
for today. Please come back tomorrow to see
portfilio comments.
</h4>
)}
{listOfUserComments}
</div>
</div>
</div>
<div className="row">
<div className="center-items col">
<h4 className="text-dark">Leave a comment</h4>
</div>
</div>
<div className="row">
<div className="center-items col">
<form className="comment-form">
<div className="form-floating mb-3">
<input
type="text"
className="bg-transparent form-control"
id="floatingInput"
name="name"
onChange={handleFormData}
/>
<label htmlFor="floatingInput">Name</label>
</div>
<div className="form-floating">
<textarea
className="form-textarea-field bg-transparent form-control mb-1"
name="comment"
id="floatingTextarea"
onChange={handleFormData}
/>
<label htmlFor="floatingTextarea">Comment</label>
</div>
<div className="d-grid">
<button
className="btn btn-primary mb-4"
onClick={() => addComment()}
>
Add Comment
</button>
</div>
</form>
</div>
</div>
</Router>
</div>
</main>
</div>
</div>
<Footer />
</div>
</>
);
}

Can't figure out how to redirect to home page

I just started watching some guide on youtube how to make simple fronend in React with bootstrap. I'm stuck for hours on one step since on react-router-dom v6 I can't use history anymore and as I'm using React class comp, I don't know how to implement "useNavigate" to my code. Thing that I want to do is when I add new book to go back to home page which is "/books". Here is my code:
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import BookService from '../services/BookService';
class CreateBookComponent extends Component {
constructor(props){
super(props)
this.state={
bookName: "",
authorName: ""
}
this.changeBookNameHandler = this.changeBookNameHandler.bind(this);
this.changeAuthorNameHandler = this.changeAuthorNameHandler.bind(this);
this.saveBook = this.saveBook.bind(this);
}
changeBookNameHandler = (event) => {
this.setState({bookName: event.target.value});
}
changeAuthorNameHandler = (event) => {
this.setState({authorName: event.target.value});
}
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
**here is where did guy in guide called this.props.history.push('books');**
});
}
render() {
return (
<div>
<div className='container mt-2'>
<div className='row'>
<div className='card col-md-6 offset-md-3 offset-md-3'>
<h1 className='text-center'>Add Book</h1>
<div className='card-body'>
<form>
<div className='form-group'>
<label> Book Name</label>
<input placeholder='Book Name' name='bookName' className='form-control'
value={this.state.bookName} onChange={this.changeBookNameHandler}/>
</div>
<div className='form-group mt-2'>
<label> Author Name</label>
<input placeholder='Author Name' name='authorName' className='form-control'
value={this.state.authorName} onChange={this.changeAuthorNameHandler}/>
</div>
<button className='btn btn-success mt-2' onClick={this.saveBook}>Save</button>
<Link to="/books" className="btn btn-danger mt-2" style={{marginLeft: '10px'}}>Cancel</Link>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default CreateBookComponent;
You can try this:
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
window.location.href = "youWebsiteUrl" + "/books"
});
}

React: Update component data/props after promise resolved

I'm a bit new to React and I've been having some problems understanding the workarounds of certain methods that I've used in other languages.
The Problem:
What I was hoping to achieve is that whenever the user clicks a button, the app will render a new section displaying some variable values. What I did was that when the user clicked a button, an state changed, and let the new Component render, and I passed the data through its props.
The problem is, If I understand correctly, that I'm passing the old values when I create the component and not the actual/updated values that I want to render...
Let's say I have this following variables.
const user_data = {
pic_url: 'null',
followers: 'Loading...',
followings: 'Loading...',
nTweets: 'Loading...',
};
Those variables are going to change value whenever the user click a button.
This next block of code is what I use to render the next component where I want the new values.
const SomeComponent = props => {
const [resolved, setResolved] = useState({ display: false });
const displayValidation = props => {
setResolved({ ...resolved, display: !resolved.display });
};
function getData(username) {
const url = 'https://www.twitter.com/' + username;
getHTML(url)
.then(res => {
getUserData(res).then(res => {
user_data.followers = res.followers;
user_data.followings = res.followings;
user_data.nTweets = res.nTweets;
user_data.pic_url = res.pic_url;
console.log('Updated data:', user_data);
displayValidation();
});
})
.catch(function(error) {
console.error('Username was not found.');
});
}
const handleSubmit = event => {
event.preventDefault();
console.log('Resolving data...');
getData(user.username);
};
return (
<React.Fragment>
<Navbar />
<div className="container lg-padding">
<div className="row" id="getTracker">
<div className="col-sm-12 center">
<div className="card text-center hoverable">
<div className="card-body">
<div className="input-field">
<i className="material-icons prefix">account_circle</i>
<input
id="username"
type="text"
className="validate"
value={user.username}
onChange={handleChange}
/>
<label htmlFor="username">Enter a username to track</label>
</div>
<input
type="button"
onClick={handleSubmit}
value="Track"
className="btn-large blue darken-4 waves-effect waves-light"
/>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-sm-12">
**{resolved.display && <DisplayData type={1} data={user_data} />}**
</div>
</div>
</div>
<Footer />
</React.Fragment>
);
};
I want to see the new values, but it always render the first values that I passed when creating the component.
This is the component that I create
import React from 'react';
const DisplayData = props => {
const user = props.data;
console.log('Display', user);
switch (props.type) {
case 1: //Twitter
return (
<React.Fragment>
<div className="row lg-padding">
<div className="col-sm-12 lg-padding center">
<img
src={user.pic_url}
alt="profile_picture"
style={{ width: 50 + '%' }}
/>
</div>
<h2>{user.username}</h2>
</div>
<div className="row lg-padding">
<div className="col-sm-4">
<h4>Tweets: {user.nTweets}</h4>
</div>
<div className="col-sm-4">
<h4>Followers: {user.followers}</h4>
</div>
<div className="col-sm-4">
<h4>Followings: {user.followings}</h4>
</div>
</div>
</React.Fragment>
);
case 2: //Instagram
return <React.Fragment />;
default:
return (
<React.Fragment>
<div className="row lg-padding">
<div className="col-sm-12 lg-padding center">
<img
src={user.pic_url}
alt="profile_picture"
style={{ width: 50 + '%' }}
/>
<h2>Instagram_User</h2>
<h4>Posts: ND</h4>
<h4>Followers: ND</h4>
<h4>Followings: ND</h4>
</div>
</div>
</React.Fragment>
);
}
};
export default DisplayData;
How can I update the data in the component or render the component when the data is updated?
Maybe your user_data might to be a state object.
// Somecomponent ...
const [user_data, setUser_data] = useState({
pic_url: 'null',
followers: 'Loading...',
followings: 'Loading...',
nTweets: 'Loading...'
})
/* Rest of stuff */
const handleSubmit = async event => {
/*...*/
const userData = await getData(user.username)
setUser_data(userData)
}
// Then display the stated-stored user_data
<div className="col-sm-12">
**{resolved.display && <DisplayData type={1} data={user_data} />}**
</div>

How do I validate textfields in a dynamic array

I have one mother component and one child component. In the child component there are two textfields (name and email) and an add button. When the user presses on add a new set of the same textfields will be rendered. I save those textfields in my mother component in an array. I want to have a validate function that checks of the values are valid. If not i want to give the error props a true value so that the user can see that field is wrong. The only problem i have is figuring out how to give right textfield in the array the error value. Because now every textfield will get the error value.
Child Component:
import React from 'react';
import TextField from '#material-ui/core/TextField';
import AddIcon from '#material-ui/icons/Add';
import Minus from '#material-ui/icons/Delete';
import Button from '#material-ui/core/Button';
class People extends React.Component {
constructor(props){
super(props);
}
render(){
const {classes} = this.props;
return (
<div>
{this.props.people.map((person, index) => (
<div key={person}>
<div className="container">
<div className="row">
<div className="col s2">
<Button
mini
variant="fab"
color="primary"
aria-label="minus"
onClick={e =>
this.props.removeRow(index)}
data-toggle="tooltip"
>
<Minus/>
</Button>
</div>
<div>
<div className="col s5">
<TextField
name="name"
id="standard-dense"
label="Teamlid naam"
margin="dense"
value={person.name}
error={e =>
this.props.validate(e, index)}
onChange={e =>
this.props.onChange(e, index)}
/>
</div>
<div className="col s5">
<TextField
name="email"
id="standard-dense"
label="Teamlid email"
margin="dense"
value={person.email}
error={e =>
this.props.validate(e, index)}
onChange={e =>
this.props.onChange(e, index)}
/>
</div>
</div>
</div>
</div>
</div>
))}
<div className="container">
<div className="row">
<div className="col s2">
<Button
mini
variant="fab"
color="primary"
aria-label="Add"
onClick={this.props.addRow}
data-toggle="tooltip"
className="btn btn-xs btn-primary"
data-original-title="">
<AddIcon/>
</Button>
</div>
<div className="col s5">
</div>
<div className="col s5">
</div>
</div>
</div>
</div>
);
}
};
export default People;
Mother Component:
import React, {Component} from 'react';
import People from './People';
class Form extends React.Component{
constructor(props){
super(props);
this.state = {
people: []
}
}
addRow = () => {
this.setState(previousState => {
return {
people: [...previousState.people, {name: "", email: "", error:false}]
};
});
};
removeRow = index => {
this.setState(previousState => {
const people = [...previousState.people];
people.splice(index, 1);
return { people };
});
};
//onChange functie van de teamleden rijen
onChange = (event, index) => {
const { name, value } = event.target;
this.setState(previousState => {
const people = [...previousState.people];
people[index] = { ...people[index], [name]: value };
return { people };
});
};
validate = (event,index) => {
event.preventDefault();
if(!event.target.value){
return true;
}else{
return false;
}
};
render(){
const {classes} = this.props;
return(
<form>
<People
addRow={this.addRow}
removeRow={this.removeRow}
onChange={this.onChange}
people={this.state.people}
validate={this.validate}
/>
<button onClick={this.validate}>Validate</button>
</form>
);
}
}
export default Form;
I know that the validate function probably needs the index of the wrong textfield. But I don't know how to properly implement it.

Categories

Resources