How to Get a specific question by Id in React - javascript

I have a question concerning Mern stack. I have a program which is similar to stackOverflow, where you post a question and someone can reply. At the moment my program is able to post questions and also get a list of all questions. I have a link at each and every questions,so that when you click at any of the questions it should open that specific question. The id of the questions is visible at the rout e.g http://localhost:3000/link/5cae2dda9723ad157c085370. The problem am having is to get the content of that specific question
//*this code is able get the list of all questions*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { EMLINK } from "constants";
const Question = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
<td>
<Link to={"/link/" + props.question._id}>comment</Link>
</td>
</tr>
);
class QuestionList extends Component {
constructor(props) {
super(props);
this.state = { questions: [] };
}
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({ questions: response.data });
})
.catch(function(error) {
console.log(error);
});
}
questionList() {
return this.state.questions.map(function(currentQuestion, i) {
return <Question question={currentQuestion} key={i} />;
});
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
<th>Action</th>
</tr>
</thead>
<tbody>{this.questionList()}</tbody>
</table>
</div>
);
}
}
export default QuestionList;
*/The below code is the one that i need to only show one specific question by ID*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const Questioners = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
</tr>
);
class QuestionLink extends Component {
constructor(props) {
super(props);
this.state = {
author_name: "",
question_title: "",
question_input: ""
};
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
</tr>
</thead>
<tbody>{}</tbody>
</table>
</div>
);
}
}
export default QuestionLink;

I've done the following in these scenarios:
Take the ID as a parameter to the Component (in this case, QuestionLink)
Retrieve the question from your REST API as a get for the particular resource (with ID) in your ComponentDidMount
When mounting your react app (top-level component), retrieve the Id from the url. I prefer to use a query string
import { parse } from "querystring";
let values = parse(window.location.search.substring(1));
And then mount <QuestionLink questionId={values["questionId"]} />
EDIT: I haven't used template engines for this, but it should be well suited for this kind of work. You can use something like pug for the server side rendering, pass the id to the view from your middleware, and render to a react component. I'd probably only do this if I did this sort of processing extensively and/or needed information that only the server had.

Thanks for help, i made it work. i solved the issue as follow
<Route
path="/link/:id"
render={props => <QuestionLink {...props} />}
/>
this.state = {
currentQuestion: {}
};
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({
currentQuestion: response.data.find(elm =>
elm._id == this.props.match.params.id
)
});
})

Related

TypeError: Cannot read property 'bind' of undefined, I can not figure what this means. React js

I ran into this error when trying to run my React code and see it's a common error but after looking at other people's questions I am having issues still how to fix this. I am still new to React so I'm kinda lost. What the code is supposed to do is take a JSON file and and display it as a table and the button is supposed to then sort it by last name and redisplay the table.
import data from './data.json' //Imports the JSON from local file, can be changed later to pull from api
import {Button, View} from 'react-native';
export default function App() {
return (
<PaientTable/>
);
}
class PaientTable extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
// this.sort = this.sort.bind(this);
}
render(){
function sort (){
return this.setState(
data.sort((a, b) => {//sorts by name
if (a.lName < b.lName) {
return -1;
}
if (a.lName > b.lName) {
return 1;
}
return 0;
})
);
}
return (
<table>
<caption>Paients</caption>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>
<button type="button" onClick={() => this.sort.bind(this)}>
Last Name
</button>
</th>
</tr>
</thead>
<tbody>
{data.map(paient => (
<tr>
<td>{paient.id}</td>
<td>{paient.fName}</td>
<td>{paient.lName}</td>
</tr>
))}
</tbody>
</table>
);
}
}
You've defined sort to be a local variable inside of render, But all the places where you try to access it you're treating it as though its a member of the class. So instead of structuring it like this:
class PaientTable extends React.Component {
// ...
render() {
function sort () {
// ...
}
// ...
}
}
Do this:
class PaientTable extends React.Component {
// ...
sort() {
// ...
}
render() {
// ...
}
}

React Matrix of Radio buttons

I tried to solve this js react problem and get stuck on questions 2-4.
Question 2: I don't know how to check the local state for each row in order to check for the duplicate rank select
Question 3: Should I need props passed to the component to check for unique?
Question 4: How do I check all rows have a select ranked and unique?
Here are the questions:
Adding a class of "done" to a row will highlight it green. Provide this
visual feedback on rows which have a selected rank.
Adding a class of "error" to a row will highlight it red. Provide this
visual feedback on rows which have duplicate ranks selected.
There is a place to display an error message near the submit button. Show
this error message: Ranks must be unique whenever the user has selected the
same rank on multiple rows.
The submit button is disabled by default. Enable it when all rows have a
rank selected and all selected ranks are unique.
The orginal App.js
import React, { Component } from 'react';
import './App.css';
import MainPage from './components/MainPage';
class App extends Component {
render() {
return (
<MainPage />
);
}
}
export default App;
MainPage.js
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" />
</div>
);
}
}
export default MainPage;
FormRow.jsx
import React from 'react';
import _ from 'lodash';
class FormRow extends React.Component {
render() {
const cells = _.range(1, 6).map((i) => {
return (
<td key={`${this.props.animalName}-${i}`}>
<input
type="radio"
name={this.props.animalName}
value={i}
/>
</td>
);
});
return (
<tr>
<th>{this.props.animalName}</th>
{cells}
</tr>
)
}
}
export default FormRow;
Animal.js
class Animal {
constructor(name, rank) {
this.name = name;
this.rank = rank;
}
}
export default Animal;
My code is at GitHub (git#github.com:HuydDo/js_react_problem-.git). Thanks for your suggestion!
FormRow.jsx
import React from 'react';
import _ from 'lodash';
class FormRow extends React.Component {
constructor(){
super();
this.state = {
rowColor : false,
name: "",
rank: 0
// panda: 0,
// cat: 0,
// capybara: 0,
// iguana: 0,
// muskrat: 0
}
}
handleChange = (e) => {
if (this.state.rank === e.target.value){
console.log("can't select same rank.")
}
console.log(e.target.name)
console.log(e.target.value)
this.setState({
// [e.target.name]: e.target.value,
name: e.target.name,
rank: e.target.value,
rowColor: true
}, console.log(this.state))
}
handleChange2 = (e) => {
let newName = e.target.name
let newRank = e.target.value
let cRank = this.state.rank
let cName = this.state.name
console.log(this.state)
console.log(`${newRank} ${newName}`)
if(cName !== newName) {
if(cRank !== newRank) {
this.setState({
name : newName,
rank: newRank,
rowColor: true
},()=> console.log(this.state))
}
else {
console.log("can't select same rank")
}
}
// this.setState(previousState => {
// let cRank = previousState.rank
// let cName = previousState.name
// console.log(previousState)
// return {
// rank: newRank,
// name: newName,
// rowColor: true
// }
// },console.log(this.state.rank))
}
render() {
const cells = _.range(1, 6).map((i) => {
return (
<td key={`${this.props.animalName}-${i}`} onChange={this.handleChange2}>
<input
type="radio"
name={this.props.animalName}
value={i}
/>
</td>
);
});
return (
<tr className = {(this.state.rowColor) ? 'done':null} >
{/* <tr> */}
<th>{this.props.animalName}</th>
{cells}
</tr>
)
}
}
export default FormRow;
MainPage.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
getValue = ({name,rank}) =>{
console.log(`Name: ${name} rank: ${rank}`)
}
// handleSubmit = event => {
// event.preventDefault()
// this.props.getValue(this.state)
// }
checkForUnique = () => {
// Show this error message: `Ranks must be unique` whenever the user has selected the
// same rank on multiple rows.
this.setState({
error : "Ranks must be unique"
})
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
handleChange={this.handleChange}
getValue={this.getValue}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} /> {/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
enter image description here
I tried to add handleChange and handleAnimalSelect methods, but I get an error. The new name and rank are not added to the arrays.
MainPage.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
getValue={this.getValue}
handleAnimalSelect={this.handleAnimalSelect}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} />
{/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
FormRow.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
getValue={this.getValue}
handleAnimalSelect={this.handleAnimalSelect}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} />
{/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
You're pretty much making a form with a few rows of multiple choice answers.
One way of simplifying everything is to have all the logic in the top component, in your case I think MainPage would be where it would be. Pass down a function as a prop to all the descendants that allows them to update the form data upstream.
In Q2, how do intend to check the state for each row? Perhaps you can use arrays or objects to keep track of the status of each question. The arrays/objects are stored in state, and you just check them to see what the status is.
I'm actually not clear what your app looks like - what does a row look like? (You might want to post a screenshot) And I don't see any way for rank to be selected - I don't even see what the ranks are for, or how they are used in the form. So perhaps your form design needs to be tweaked. You should begin the form design with a clear picture in YOUR mind about how the app will work. Maybe start by drawing the screens on paper and drawing little boxes that will represent the objects/array variables and go through the process of a user using your app. What happens to the various boxes when they click radio buttons and so on. How will you know if the same rank is selected twice - where are the selected ranks stored? What animals are clicked/selected? Where are those stored? Draw it all on paper first.
Array or objects: If you want to keep it simple, you can do the whole project just using arrays. You can have one array that stores all the animals. You can have a different array that stores which animals are selected right NOW (use .includes() to test if an animal is in that array). You can have another array that stores the rows that have a rank selected. When the number of elements in that row === the number of rows (is that the same as the number of animals? If yes, then you can use the length of the animals array for that test)
How do you know if the rows with a rank selected are unique? One way is to DISALLOW selected a rank that has already been selected. Again, use .includes() (e.g. arrSelectedRanks.includes(num)) to check if a rank has already been selected.
SO what do one of these checks look like?
const handleAnimalSelect = (animal) => {
const err = this.state.selectedAnimals.includes(animal);
if (err === true){
this.setState(error: animal);
}
}
return (
<input
type="radio"
name={this.props.animalName}
value={i}
onClick={this.handleAnimalSelect}
/>
{ error !== undefined && (
<div class={style.errorMessage}>{`Animal ${} was chosen twice`}</div>
)}
);
};
Remember: State is what you use for remembering the value of variables in a given component. Every component has its own state. But Props are for data/functions/elements that are passed into the component. You don't update the values of props in the component (prop values are stored in another component. If you need to update them, you use functions to pass data back to the parent component where that variable is in state, and update the value there).
Here is an example that uses .includes() to check for the presence/absence of something:
https://stackoverflow.com/a/64486351/1447509

Why this error arising? users.map is not a function

I am trying to render names from a API with Axios. Even I can see all data in console but unable to render as it shows error:
users.map is not a function
Below I'm sharing my code of the file. I'm quite new that might be the reason I'm unable to figure it out.
import React from 'react';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import { Container, Table} from "react-bootstrap";
import axios from 'axios';
class App extends React.Component {
state = {
users: [],
};
componentDidMount () {
axios.get('https://5w05g4ddb1.execute-api.ap-south-1.amazonaws.com/dev/profile/listAll')
.then(response => {
const users = response.data;
this.setState({ users });
console.log(this.state.users);
})
}
render() {
const { users } = this.state;
return (
<div className="App">
<Container fluid>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th><div id="">Image</div></th>
<th>Name</th>
<th>Gender</th>
<th>Age</th>
<th>Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
{ users.map(user => { return <td key={user.id}>{ user.name }</td> }) }
</tr>
</tbody>
</Table>
</Container>
</div>
)
}
}
export default App;
The response you are getting is not an array, but an object like this:
{"list":[{"id":"MnJJA0dbuw","name":"Anand Sharma","img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Anand.jpeg","gender":"m","age":46,"date":"23/11/2019","status":"onboarded"}]}
You can access the array by replacing const users = response.data; with const users = response.data.list;
In your axios get, in the “then” part change the line:
const users = response.data;
To:
const users = response.data.list;
fast hack
{users.list.map(user => { return <td key={user.id}>{ user.name }</td> }) }
There are 2 errors:
the response from api is not a list but an object, u need to go to response.list to use the list from the response
it should be
const users = response.data.list
your
this.setState({users})
,you will need to change it to
this.setState({users:<VARIABLE_NAME_TO_HOLD_USER_DATA>})
even what you write is valid like in ES6, that is somehow a bad idea, it is not a clear what are you doing, just define what u want to copy to ur component state

Error in reading and viewing Firebase data from React-JS

I just need to view my stored data in firebase on the HTML content using ReactJs. But I got lots of error while running it. The main issue I think is data not set to the this.state with this.setState command. Here is my code.
import React, {Component} from 'react';
import {database} from "../firebase/firebase";
class MempoolTable extends Component {
constructor() {
super();
this.state = {
items:null
};
}
componentDidMount(){
let reportRef = database.ref("mempool");
let newState = [];
reportRef.once("value").then((snapshot) => {
snapshot.forEach((childSnapshot) => {
let items = childSnapshot.val();
newState.push({
time: items.time,
hash: items.hash,
size: items.size,
weight: items.weight
});
});
this.setState({ items: newState })
});
console.log(this.state);
}
render() {
return(
<div className="row" style={{marginTop: "30px"}}>
<h4 style={{textAlign: "center", color: "#4D4F4E"}}><b>Memory Pool</b></h4>
<h6 style={{textAlign: "center", color: "#4D4F4E"}}>(no of txs: 14, size: 168.81 kB)</h6>
<div className="col-xl-9 mx-auto" style={{marginTop: "10px"}}>
<table id="memPool" className="table table-bordered">
<thead>
<tr className="table-striped">
<th>AGE [H:M:S]</th>
<th>TRANSACTION HASH</th>
<th>FEE</th>
<th>TX SIZE[KB]</th>
</tr>
</thead>
<tbody>
{this.state.items.map(item => {
return (
<tr>
<td>{item.time}</td>
<td>{item.hash}</td>
<td>{item.size}</td>
<td>{item.weight}</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
);
}
}
export default MempoolTable;
This is the error I got. Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. And sometimes it shows me error like this. TypeError: Cannot read property 'map' of null
I just need to get all the data from firebase and load those data into the state. Then load those data on render part. Can someone help me to fix this issue?
Your initializing the state with null:
this.state = {
items:null
};
and callback from accessing database is asynchronous, so the render method will be called before the callback and will throw the error :
TypeError: Cannot read property 'map' of null
Given the error on the render method component wont mount, and this.setState from callback is being invoked on an unmounted component.
Possivel workarounds
Instantiate items to an empty array :
this.state = {
items:[]
};
Or prevent map for being executed on a null object:
{this.state.items ? this.state.items.map(item => {
return (
<tr>
<td>{item.time}</td>
<td>{item.hash}</td>
<td>{item.size}</td>
<td>{item.weight}</td>
</tr>
)
})
: ''}

ReactJS: React Component not rendering

ContactList.js
var React = require('react');
var Contact = require('./contact.js');
var ContactList = React.createClass({
render: function() {
return(
<div>
<h3>Contacts</h3>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.props.contacts.map(function(contact, index) {
<Contact contact={contact} key={index} />
})
}
</tbody>
</table>
</div>
)
}
Contact.js
var React = require('react');
var Contact = React.createClass({
render: function() {
return(
<tr>
<td>{this.props.contact.name}</td>
<td>{this.props.contact.phone}</td>
<td>{this.props.contact.email}</td>
</tr>
)
}
})
module.exports = Contact;
Basically, i am able to get the contacts data from firebase in console but i want to display all the contacts i saved in the table. Behind the scenes, there is react-flux setup. State 'contacts' is basically an object inside an array, when i go to react tools, i can't see Contact component there, also if i try to console.log something to verify nothing works in Contact component, it seems like props is not passing to Contact component, also sometimes i get
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. don't know whether it is because of this.
Can somebody explain me what is wrong ? Thanks in advance!!.
You need to send props to ContactList.js i.e, the response.data that you get after hitting firebase.
Something like this:-
React.render(<ContactList contacts= 'your response object' />);
Check whether your passing or not.
To solve it more easily you can use React.Component ,
ContactList.js
import React from 'react';
import Contact from './contact'
class ContactList extends React.Component {
{contacts}=this.props;
render(){
return(
<div>
<h3>Contacts</h3>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
contacts.map(function(contact, index) {
<Contact contact={contact} key={index} />
})
}
</tbody>
</table>
</div>
)
}
}
export default ContactList
Contact.js
import React from 'react'
class Contact extends React.Compponet{
{contact}=this.props;
render() {
return(
<tr>
<td>{contact.name}</td>
<td>{contact.phone}</td>
<td>{contact.email}</td>
</tr>
)
}
}
export default Contact
You have to pass the props to the ContactList class which would internally pass it to Contact.
Thank you.
You need to return the Contact component inside the ContactList component like this:
this.props.contacts.map(function(contact, index) {
return <Contact contact={contact} key={index} />
})
or, you can use arrow function:
this.props.contacts.map((contact, index) => <Contact contact={contact} key={index} />)

Categories

Resources