Some Problem in Params, Not getting the Emp id ? possible solution - reactjs

Error Are : Uncaught TypeError: Cannot read properties of undefined (reading 'params'),
The above error occurred in the component:
I might think i problem is in the passing props
App component
class App extends Component {
render() {
return (
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Navigate to={"/card"} />}></Route>
<Route path="/card" element={<Card />} />
<Route path="/edit/:id" element={<EditEmployee />} />
</Routes>
</BrowserRouter>
);
}
}
card Component
const emp1 = {
empId: 100,
empName: "Jack",
age: 30,
salary: 50000,
image: image1,
achievements:
"Has got 3 bravo awards and 1 MVP award. Has worked on cutting edge technologies as well",
};
const emp2 = {
empId: 101,
empName: "Jane",
age: 24,
salary: 40000,
image: image2,
achievements: "No major achievements so far",
};
export default class Card extends React.Component {
empArr = [emp1, emp2];
render() {
return (
<div>
<h3 className="text-center text-primary">Employee Details</h3>
<div className="row">
{this.empArr.map((emp) => (
<Employee key={emp.empId} emp={emp} />
))}
</div>
</div>
);
}
}
Employee Component
class Employee extends React.Component {
state = {
achievements: null,
edit: null,
};
handleEdit = () => {
this.setState(() => ({ edit: true }));
};
handleView = () => {
this.setState(() => ({ achievements: this.props.emp.achievements }));
};
render() {
const { emp } = this.props;
if (this.state.edit) {
return <Navigate to={"/edit/" + emp.empId} push></Navigate>;
}
return (
<div className="card" style={{ width: 200 }}>
<img
className="card-img-top"
src={emp.image}
height="200"
alt="Card cap"
/>
<div className="card-body">
<h5 className="card-title text-center">{emp.empName}</h5>
<p className="card-text">
<span>Id: {emp.empId}</span>
<br />
<span>Age: {emp.age}</span>{" "}
{emp.age < 25 && <span className="text-info"> - Fresher</span>}
<br />
<span>Salary: {emp.salary}</span>
<br />
</p>
<p>
<i>{this.state.achievements}</i>
</p>
<button
type="button"
className="btn btn-primary"
onClick={this.handleEdit}
>
Edit
</button>
<button className="btn btn-success" onClick={this.handleView}>
View
</button>
</div>
</div>
);
}
}
EditEmployee Component
class EditEmployee extends React.Component {
render() {
return <h3>The selected ID is {this.props.match.params.id}</h3>;
}
}
export default EditEmployee;
Result should be like this
WHAT I WANT
but i am getting this error on click edit
enter image description here
WHAT I AM GETTING /ERROR IMAGE

You want to get the params via the useParams() hook:
const EditEmployee = () => {
const id = useParams()
return (
<h3>The selected ID is {id}</h3>;
)
}
export default EditEmployee;
Sorry that's a functional component. You can translate it to a class...
Did you just console.log(this.props) in your EditEmployee to see what you're getting?
You may need to wrap your class component in a function component as illustrated here.
Documentation here

Related

Remove item from array react js

I'm having trouble with removing an object from an array. I have tried many options and nothing works.
Please help me solve this problem.
Thanks for your help
My array:
export const SavedList = [
{
word: 'hello',
translate: 'привет',
note: 'say say'
}
]
Remove callback (deletePost)
class Menu extends Component {
state = {
word: '',
translate: '',
note: '',
data: SavedList,
}
deletePost =(id)=>{
this.setState({
data : this.state.data.filter((el)=> el.id !== id)
})
}
render() {
return (
<div className="content">
<Routes>
<Route path="/" element={<Layout />}>
<Route path="saved" element={<Saved data={this.state.data} del={this.deletePost}/>}/>
</Route>
</Routes>
<div>
</div>
</div>
);
}
}
export default Menu;
here button delete with onClick
class Saved extends Component {
render() {
const sl = this.props.data.map((sl, id) => {
return (
<div className="saved-card" key={id}>
<div className="content">
<p>{id}</p>
<p>{sl.word}</p>
<p>{sl.translate}</p>
<p>{sl.note}</p>
</div>
<div className="btn-block">
<button
onClick={() => this.props.del(id)}
type="button"
className="delete-btn"
>
delete
</button>
</div>
</div>
);
});
return (
<div>
<h2>Saved list</h2>
<div className="saved-inner">
<div className="saved-list">{sl}</div>
</div>
</div>
);
}
}
export default Saved;
This issue is because el.id doesn't have any value in delete Post Function. That function also needs to have an ID variable, I have named it as i_di.
class App extends Component {
state = {
word: '',
translate: '',
note: '',
data: SavedList,
}
deletePost =(id)=>{
this.setState({
data : this.state.data.filter((el, i_di)=> i_di !== id )
})
}
render() {
return (
<div className="content">
{<Saved data={this.state.data} del={this.deletePost}/>}
</div>
);
}
}
export default App;

How do I preserve previous state of React InstantSearch

import React, { Component, useState } from 'react';
import algoliasearch from 'algoliasearch/lite';
import {
InstantSearch,
Hits,
SearchBox,
Highlight,
connectRefinementList,
} from 'react-instantsearch-dom';
import PropTypes from 'prop-types';
import './App.css';
const searchClient = algoliasearch(
'test',
'test'
);
class App extends Component {
constructor(props) {
super(props);
this.state = {
selectedCountries: []
}
}
render() {
const RefinementList = ({
items,
isFromSearch,
refine,
searchForItems,
createURL,
}) => {
return (
<ul style={{ listStyle: 'none' }}>
{
items &&
items.map(item => (
<li key={item.label}>
<input
type="checkbox"
checked={item.isRefined}
// href={createURL(item.value)}
style={{ fontWeight: item.isRefined ? 'bold' : '' }}
onChange={event => {
// event.preventDefault();
refine(item.value);
}}
/>
{isFromSearch ? (
<Highlight attribute="label" hit={item} />
) : (
item.label
)}{' '}
({item.count})
</li>
))}
</ul>
)
};
const CustomRefinementList = connectRefinementList(RefinementList);
return (
<div className="container">
<InstantSearch searchClient={searchClient} indexName="parterns">
<div className="search-panel">
<div className="search-panel__results">
<SearchBox
className="searchbox"
translations={{
placeholder: '',
}}
searchAsYouType={false}
/>
<Hits hitComponent={Hit} />
<br />
<br />
<button onClick={(e) => {
const that = this;
e.preventDefault();
that.setState({
selectedCountries: Array.from(new Set([...that.state.selectedCountries, 'India']))
})
}
}
>
Select India
</button>
<br />
<button onClick={(e) => {
const that = this;
e.preventDefault();
that.setState({
selectedCountries: Array.from(new Set([...that.state.selectedCountries, 'USA']))
})
}
}
>
Select Usa
</button>
<br />
<h3>Location</h3>
<div className="region">
<CustomRefinementList
operator="or"
limit={10}
defaultRefinement={[]}
attribute="region" />
</div> <br />
<CustomRefinementList
operator="or"
limit={this.state.selectedCountries.length}
defaultRefinement={this.state.selectedCountries}
attribute="country" />
<br />
<br />
</div>
</div>
</InstantSearch>
</div>
);
}
}
function Hit(props) {
return (
<article onClick={() => alert(props.hit.title)}>
<h1>
<Highlight attribute="title" hit={props.hit} />
</h1>
</article>
);
}
Hit.propTypes = {
hit: PropTypes.object.isRequired,
};
export default App;
The problem is all previously selected filters are getting cleared.
For example initially I click on filter ex: North America
So I will get filtered results for North America.
Now I want to have Country filter which will be visible when click on button ex Select USA
When I am clicking on Button for ex: Select USA then I am setting state because I want to render it dynamically but issue is previous state is getting cleared how can I preserve previous state for component.

Problem to render a component dynamically with React Router

I'm working on a personal website and I have a problem rendering a component dynamically using React Router. To me, everything seems correct but for some reason, it's not working.
I tried to follow the documentation and watched a couple of tutorials but I have been stuck for a long time so I feel like I need help on this one.
In this component, I want to render the 'Articles' component dynamically using the id
class JobCard extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentWillMount() {
fetch(url)
.then(data => data.json())
.then(result =>
this.setState({
data: result
})
);
}
render() {
const { match } = this.props;
const { data, value } = this.state;
return (
<>
<div>
{results.map((job, id) => (
<div key={id}>
<div key={job._id} className="blog-card">
<div className="meta">
<div className="photo">
<img src={job.img} alt="logo" />
</div>
</div>
<div className="description">
<h5>{job.position_name}</h5>
<p className="read-more">
<p>{job.location}</p>
<p>
<span className="learn-pow">
{" "}
<Link
to={{
pathname: `${match.url}/${job._id}`,
state: job
}}
>
{job.workplace_name}
</Link>{" "}
Enter Location
</span>
</p>
</p>
</div>
</div>
</div>
))}
</div>
}
<Route path={`${match.path}/:id`} component={Articles} />
</>
);
}
}
export default JobCard;
And here is the component that i want to render:
import React from 'react';
const Articles = ({ location }) => (
<div>
<h1>{location.state.name}</h1>
<h2>{location.state.email}</h2>
<h2>{location.state.place}</h2>
</div>
)
export default Articles;
When I click on the Card the URL is right so I get the id but I don't have access to the Article component. I tried to console log but nothing appears.
Instead of this
<Route path={`${match.path}/:id`} component={Articles} />
try doing this
<Route path={`${match.url}/:id`} component={Articles} />

How to pass props through router

I have a list of task, on my dashboard, I want as soon as clicked on a task to get his details.
At the moment I can only retrieve the id of this task, but can't get other information.
When I console.log listTask on my parent component, I get an Array objects that contains all the task:
[ 0: Object { state: "Started", date: "2019-02-11T19:57:26.176Z", _id: "5c6074afd2f8eb5019fd5f54", … }
1: Object { state: "Started", date: "2019-02-11T19:57:26.176Z", _id:"5c60798bacf119510c19f5b1", … }
2: Object { state: "Started", date: "2019-02-11T19:57:26.176Z", _id: "5c607be3c11c2b529615ac26", … }
3: Object { state: "Started", _id: "5c607cfec27d6254c6fe0ca1", projectName: "I LOVE THIS GAME", … } ]
parentComponent.js
async componentDidMount() {
this._isMounted = true
let response = await fetch(`http://localhost:5001/userproject/${taskId}`)
let data = await response.json()
console.log(data) // will show me the array
const projects = data.map(pro => {
return {
id: pro._id,
state: pro.state,
projectName: pro.projectName,
consultants: pro.consultants,
ScrumMasterUsername: pro.scrumMaster.username,
ScrumMasterId: pro.scrumMaster._id,
}
})
return this.setState({
projects: { projects },
})
}
render() {
const { projects } = this.state
const list = (projects && projects.projects) || []
if (!projects) {
return null
}
return (
<div className="dashboard container">
<div className="row">
<div className="col s16 m7 darken-2">
<ProjectList
name={this.state.projects.projectName}
projects={list}
/>
</div>
<div className="col s12 m3 offset-m1">
<Notifications />
</div>
</div>
</div>
)
}
My problem: When tried to get the task details, it retrieves the id of this task and not the other detail:
import React from 'react'
const ProjectDetails = props => {
const id = props.match.params.id
console.log(props) // i can only get the id
return (
<div className="container section project-details">
<div className="card z-depth-0">
<div className="card-content">
<span className="card-title">Project Title - {id} </span>
</div>
</div>
</div>
)
}
export default ProjectDetails
This is how you should do it.
class App extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route path="/" component={Home} />
**<Route path="/about" render={(props) => <About {...props} isAuth={"Authenticated"} />} />**
<Route path="/topics" component={Topics} />
</Switch>
</div>
</Router>
);
}
}
The second route marked between stars, is the one where I am rendering the component and passing a prop isAuth={"Authenticated"}
The above prop will be available inside About component as
const About = (props) => {
return (
<div>
<h1>About={props.isAuth}</h1>
</div>
);
}
Hope this helps you!!

React app state not updating

I am creating a basic React app to hold books on certain shelves and am trying to create the functionality to move books between shelves.
The problem I have is that when I select the new target shelf from the book objects dropdown, the onUpdateShelf method in ListBooks.js does not seem to initiate the update and subsequent state change.
I am new to React, my understanding is that calling the setState function in updateShelf should trigger the re-render with the updated object.
My question then is, is my implementation wrong and where?
App.js
import React, { Component } from 'react'
import ListBooks from './ListBooks'
import * as BooksAPI from './utils/BooksAPI'
import { Route } from 'react-router-dom'
class BooksApp extends Component {
state = {
books: []
}
componentDidMount() {
BooksAPI.getAll()
.then((books) => {
this.setState(() => ({
books
}))
})
}
updateShelf = (book, shelf) => {
console.log(book)
console.log(shelf)
this.books.forEach(b => {
if(b.id === book.id && b.shelf !== book.shelf ) {
b.shelf = shelf
this.setState((currentState) => ({
books: currentState.books
}))
}
});
BooksAPI.update(book, shelf)
}
render() {
return (
<div>
<Route exact path='/' render={() => (
<ListBooks
books={this.state.books}
onUpdateShelf={this.updateShelf}
/>
)} />
</div>
)
}
}
export default BooksApp
And my ListBooks.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import './App.css'
const shelves = [
{
key: 'currentlyReading',
name: 'Currently Reading'
},
{
key: 'wantToRead',
name: 'Want To Read'
},
{
key: 'read',
name: 'Read'
}
];
class ListBooks extends Component {
static propTypes = {
books: PropTypes.array.isRequired
}
state = {
showSearchPage: false,
query: ''
}
render() {
const { books, onUpdateShelf } = this.props
function getBooksForShelf(shelfKey) {
return books.filter(book => book.shelf === shelfKey);
}
console.log(books);
return(
<div className="app">
{this.state.showSearchPage ? (
<div className="search-books">
<div className="search-books-bar">
<a className="close-search" onClick={() => this.setState({ showSearchPage: false })}>Close</a>
<div className="search-books-input-wrapper">
{/*
NOTES: The search from BooksAPI is limited to a particular set of search terms.
You can find these search terms here:
https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
you don't find a specific author or title. Every search is limited by search terms.
*/}
<input type="text" placeholder="Search by title or author"/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid"></ol>
</div>
</div>
) : (
<div className="list-books">
<div className="list-books-title">
<h1>My Reads</h1>
</div>
<div className="list-books-content">
<div>
{ shelves.map((shelf) => (
<div key={shelf.key} className="bookshelf">
<h2 className="bookshelf-title">{shelf.name}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
<li>
{ getBooksForShelf(shelf.key).map((book) => (
<div key={book.id} className="book">
<div className="book-top">
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks.thumbnail})` }}></div>
<div className="book-shelf-changer">
<select>
<option value="none" disabled>Move to...</option>
<option value="currentlyReading" onClick={() => onUpdateShelf(book, 'currentlyReading')} >Currently Reading</option>
<option value="wantToRead" onClick={() => onUpdateShelf(book, 'wantToRead')} >Want to Read</option>
<option value="read" onClick={() => onUpdateShelf(book, 'read')} >Read</option>
<option value="none" onClick={() => onUpdateShelf(book, '')} >None</option>
</select>
</div>
</div>
<div className="book-title">{book.title}</div>
<div className="book-authors">{book.author}</div>
</div>
))}
</li>
</ol>
</div>
</div>
)) }
</div>
</div>
<div className="open-search">
<a onClick={() => this.setState({ showSearchPage: true })}>Add a book</a>
</div>
</div>
)}
</div>
)
}
}
export default ListBooks
When you passe updateShelf to your component ListBooks, you lose the value of this inside updateShelf, and as a result this.books will be undefined.
You can solve this by, either doing this inside the constructor of BooksApp :
this.updateShelf = this.updateShelf.bind(this)
Or by using arrow functions:
<Route exact path='/' render={() => (
<ListBooks
books={this.state.books}
onUpdateShelf={() => { this.updateShelf()} }
/>
)} />
EDIT
You are already using arrow functions inside BooksApp, so what I said before isn't necessary.
But still, you should use this.state.books and not this.books inside updateShelf.

Resources