React sending props withoutid - reactjs

<Description
description={description}
/>
In Description component I can display name and other pool but not id. I diplay in console.log what is in this props and it is all without id, created_at and updated_at. Why? How can I send props with id? Let me just mention that in parent component everything is ok.
#Update
export default function Description({description}){
const showDescription = (description) => {
console.log(description);
}
return(
<div>
<h2>{description.id} {description.title}</h2>
<div><button onClick={ () => showDescription(description) }
>Click</button></div>
</div>
);
}
#Update2
For the test I tryed send id like a new props. I show you too more code
<>
<ul>
{descriptions.map(description =>
{description.id}
<li
key={description.id}>
{description.id} <span onClick={
() => handleClick(desscription)}>{description.na
me}
</span>
</li>)}
</ul>
<Description
id={description.id}
description={description}
/>
</>
React display id in list (li) but if I send that in props, Description component desplay undefined.

import Description from "./Description";
export default function App() {
const descriptions = [
{ id: 1, title: "Foo", name: "Alex" },
{ id: 2, title: "Bar", name: "Mike" }
];
const handleClick = (d) => {
console.log(d);
};
return (
<div>
<ul>
{descriptions.map((description) => (
<li key={description.id}>
<span onClick={() => handleClick(description)}>
{description.name}
</span>
</li>
))}
</ul>
<Description id={descriptions.id} description={descriptions} />
</div>
);
}
Source: Difference between {} and () with .map with Reactjs
Example 1:
Example 2:
I have created the following demo:
https://codesandbox.io/s/divine-currying-xdt7w?file=/src/App.js

Related

How can I create Single Page

How can I pass map items (title, category and images) in my id.jsx file.
Basically, I just want to create a single page for my projects. But I can only access post ID. I don't know how to pass other data items.
'Projects folder'
[id].js
import { useRouter } from "next/router";
const Details = () => {
const router = useRouter();
return <div>Post #{router.query.id}
// Single Project Title = {project.title} (like this)
</div>;
};
export default Details;
index.js
import { MyProjects } from "./MyProjects";
const Projects = () => {
const [projects, setProjects] = useState(MyProjects);
{projects.map((project) => (
<Link
href={"/projects/" + project.id}
key={project.id}
passHref={true}
>
<div className="project__item">
<div className="project__image">
<Image src={project.image} alt="project" />
</div>
<div className="project_info">
<h5>{project.category}</h5>
<h3>{project.title}</h3>
</div>
</div>
</Link>
))}
If I understand your question correctly, you want to send some "state" along with the route transition. This can be accomplished using an href object with the "state" on the query property, and the as prop to hide the query string.
Example:
{projects.map((project) => (
<Link
key={project.id}
href={{
pathname: "/projects/" + project.id,
query: {
id: project.id,
category: project.category,
title: project.title
}
}}
passHref={true}
as={"/projects/" + project.id}
>
<div className="project__item">
<div className="project__image">
<Image src={project.image} alt="project" />
</div>
<div className="project_info">
<h5>{project.category}</h5>
<h3>{project.title}</h3>
</div>
</div>
</Link>
))}
...
const Details = () => {
const router = useRouter();
return (
<div>
<div>Post #{router.query.id}</div>
<div>Title {router.query.title}</div>
<div>Category {router.query.category}</div>
</div>
);
};

How do I conditionally render pages with a dropdown menu in React?

I'm fairly new to React and I'm working on a website for a friend that uses a lot of react features. One thing this website needs is a navbar where every item in the navbar has a dropdown selection of additional nav items. I'm able to both render pages conditionally as independent nav items and create the hover dropdown on each nav item, but my issue comes into merging them together. I've tried a few things such as mapping through props twice, creating a large object where the nav item is a name and the dropdown items are subnames, but neither of those worked.
Here is the code I'm using:
function Nav(props) {
const [navItemList, setNavItemList] = useState([
{name: 'About', dropdownItem1: 'About Me', dropdownItem2: 'About Tampa Bay', id: 1},
]);
const { pages = [], setCurrentPage, currentPage } = props;
return (
<header className="flex-row">
<h1 class="name-tag">
<img src={"../../assets/Logo1.png"} />
</h1>
<nav>
<NavItems items={navItemList} />
<ul className="flex-row nav-list">
{pages.map(navItem => (
<li className={`li-spacing text-format ${currentPage.name === navItem.name && 'navActive'}`} key={navItem.id}>
<span onClick={() => { setCurrentPage(navItem) }}>{navItem.name}</span>
</li>
))}
</ul>
</nav>
</header>
)
}
function App() {
const [pages] = useState([
{
id: 1,
name: 'Home'
},
{
id: 2,
name: 'About Me'
},
{
id: 3,
name: 'About Tampa Bay'
},
])
const [currentPage, setCurrentPage] = useState(pages[0])
return (
<div>
<Nav
pages={pages}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
></Nav>
<main>
<Pages currentPage={currentPage}></Pages>
</main>
</div>
);
}
function NavItems(props) {
const items = props.items
return (
<ul className=" flex-row nav-list">
{/* map through the props so each navitem receives unique information */}
{items.map((navItem) => (
<div className="dropdown" key={navItem.id}>
<li className="nav-list-item">{ navItem.name }</li>
<div className="dropdown-item">
<p>{ navItem.dropdownItem1 }</p>
<p>{ navItem.dropdownItem2 }</p>
</div>
</div>
)) }
</ul>
)
}
export default NavItems;
Something like this maybe? This might need to be adjusted a bit to fit your styling needs.
const pages = {
home: {
name: 'Home',
subPages: {},
},
about: {
name: 'About',
subPages: {
aboutMe: {
name: 'About Me',
},
aboutTampaBay: {
name: 'About Tampa Bay',
},
},
},
}
function App() {
const [currentPageKey, setCurrentPageKey] = useState('home')
return (
<div>
<Nav pages={pages} currentPage={currentPage} setCurrentPageKey={setCurrentPageKey} />
<main>
<Pages currentPage={pages[currentPageKey]} />
</main>
</div>
)
}
function Nav(props) {
const { setCurrentPageKey, currentPage, pages } = props
return (
<header className="flex-row">
<h1 class="name-tag">
<img src={'../../assets/Logo1.png'} />
</h1>
<nav>
<ul className="flex-row nav-list">
{Object.entries(pages).map(([key, { name, subPages }]) => (
<li className={`li-spacing text-format ${currentPage.name === name && 'navActive'}`} key={key}>
<NavItems setCurrentPageKey={setCurrentPageKey} title={name} items={subPages} />
<button onClick={() => setCurrentPageKey(key)}>{name}</button>
</li>
))}
</ul>
</nav>
</header>
)
}
export default function NavItems(props) {
const { setCurrentPageKey, items, title } = props
return (
<ul className="flex-row nav-list">
<div className="dropdown">
<li className="nav-list-item">{title}</li>
<div className="dropdown-item">
{/* map through the props so each navitem receives unique information */}
{Object.entries(items).map(([key, { name }]) => (
<button onClick={() => setCurrentPageKey(key)} key={key}>
{name}
</button>
))}
</div>
</div>
</ul>
)
}

trying to use a function that return a button component but nothing get rendered

I am trying to use a function that return a button component but when calling this function, the button component didn't render. Everything rendered except this function. I have no errors no warnings and i have tried to separate this function in a separate file but still no rendering for that function.
I am using react-bootstrap. the function i am trying to call is activeProcessingBtn
const activeProcessingBtn = () => {
return (
<div>
<Button variant="primary" disabled>
<Spinner
as="span"
animation="grow"
size="sm"
role="status"
aria-hidden="true"
/>
processing...
</Button>
</div>
);
};
function Machines() {
const [machineInfo, setMachineInfo] = useState({
id: 0,
name: "Choose Machine"
});
const [isProcessing, setIsProcessing] = useState(true);
const Machiness = [
{ id: 1, name: "Machine1" },
{ id: 2, name: "Machine2" },
{ id: 3, name: "Machine3" }
];
const selectHandler = (NewName, NewID) => {
setMachineInfo({ id: NewID, name: NewName });
};
const AddMachinesToDropDownItem = Machiness.map(({ id, name }) => {
return (
<Dropdown.Item
eventKey={id}
value={name}
className="DropdownItem"
onClick={() => selectHandler(name, id)}
>
{name}
</Dropdown.Item>
);
});
return (
<div>
<h6> Get attendance Manually </h6>
<DropdownButton id="DropDownMenu" title={machineInfo.name}>
{AddMachinesToDropDownItem}
</DropdownButton>
<activeProcessingBtn />
</div>
);
}
export default Machines;
Instead of trying to treat it like a component (<activeProcessingBtn />), call it as a function.
return (
<div>
<h6> Get attendance Manually </h6>
<DropdownButton id="DropDownMenu" title={machineInfo.name}>
{AddMachinesToDropDownItem}
</DropdownButton>
// See here
{activeProcessingBtn()}
</div>
);
All component names should start with an uppercase letter. This is what React uses to figure out whether it should consider an element a native HTML element and pass it over to the browser or further resolve what it renders. So your best option would be to rename the function to ActiveProcessingBtn or ActiveProcessingButton.

Error in Component Output by Button Click

I have 2 buttons and information about div. When I click on one of the buttons, one component should appear in the div info. Where is the error in the withdrawal of the component div info?
import React, { Component } from 'react';
import Donald from '/.Donald';
import John from '/.John';
class Names extends Component {
state = {
array:[
{id:1,component:<Donald/>, name:"Me name Donald"},
{id:2,component:<John/>, name:"My name John"},
],
currComponentId: null
changeComponentName = (idComponent) => {
this.setState({currComponentId:idComponent});
};
render() {
return(
<table>
<tbody>
<tr className="content">
{
this.state.array.map(item=> item.id===this.element.id).component
}
</tr>
<button className="Button">
{
this.state.array.map( (element) => {
return (
<td key={element.id}
className={this.state.currComponentId === element.id ? 'one' : 'two'}
onClick={ () => this.changeComponentName(element.id)}
>{element.name}
</td>
)
})
}
</button>
</tbody>
</table>
)
}
}
export default Names;
You have several problems here, the first being that you are missing the closing curly bracket on your state. this.element.id is also undefined, I assume you are meaning this.state.currComponentId.
Your html is also fairly badly messed up, for example you are inserting multiple <td>s into the content of your button. I also don't see where this.changeComponentName() is defined, so I am assuming you mean this.showComponent()
The primary issue is probably in this.state.array.map(item=> item.id === this.element.id).component, as map() returns an array. An array.find() would be more appropriate, though you still need to check to see if there is a match.
I might re-write your component like this (I have swapped out the confusing html for basic divs, as I'm not sure what you are going for here)
class Names extends Component {
state = {
array: [
{ id: 1, component: <span>Donald</span>, name: "Me name Donald" },
{ id: 2, component: <span>John</span>, name: "My name John" },
],
currComponentId: null,
};
showComponent = (idComponent) => {
this.setState({ currComponentId: idComponent });
};
render() {
//Finding the selected element
const selectedElement = this.state.array.find(
(item) => item.id === this.state.currComponentId
);
return (
<div>
<div className="content">
{
//Check to see if there is a selected element before trying to get it's component
selectedElement ? selectedElement.component : "no selected."
}
</div>
{this.state.array.map((element) => {
return (
<button
className="Button"
key={element.id}
className={
this.state.currComponentId === element.id ? "one" : "two"
}
onClick={() => this.showComponent(element.id)}
>
{element.name}
</button>
);
})}
</div>
);
}
}
Errors:- (1) You are showing list inside tag, instead show as <ul><li><button/></li></ul>(2)You are not displaying content after comparison in map()This is a working solution of your question.
class Names extends React.Component {
state = {
array: [
{ id: 1, component: <Donald />, name: "Me name Donald" },
{ id: 2, component: <John />, name: "My name John" }
],
currComponentId: null
};
clickHandler = idComponent => {
this.setState({ currComponentId: idComponent });
};
render() {
return (
<div>
<ul>
{this.state.array.map(element => {
return (
<li key={element.id}>
<button
className="Button"
onClick={() => this.clickHandler(element.id)}
>
{element.name}
</button>
</li>
);
})}
</ul>
{this.state.array.map(data => {
if (this.state.currComponentId === data.id)
return <div>{data.component}</div>;
})}
</div>
);
}
}
const Donald = () => <div>This is Donald Component</div>;
const John = () => <div>This is John Component</div>;
ReactDOM.render(<Names />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root' />

Update list of displayed components on deletion in React

in the beginning on my path with React I'm creating simple to-do app where user can add/remove task which are basically separate components.
I create tasks using:
addTask(taskObj){
let tasksList = this.state.tasksList;
tasksList.push(taskObj);
this.setState({tasksList : tasksList});
}
I render list of components (tasks) using following method:
showTasks(){
return (
this.state.tasksList.map((item, index) => {
return <SingleTask
taskObj={item}
removeTask = {(id) => this.removeTask(id)}
key = {index}/>;
})
);
}
method to remove specific task takes unique ID of task as an argument and based on this ID I remove it from the tasks list:
removeTask(uID){
this.setState(prevState => ({
tasksList: prevState.tasksList.filter(el => el.id != uID )
}));
}
But the problem is, when I delete any item but the last one, it seems like the actual list of components is the same only different objects are passed to those components.
For example:
Lets imagine I have 2 created componentes, if I set state.Name = 'Foo' on the first one, and state.Name='Bar' on the second one. If I click on remove button on the first one, the object associated to this component is removed, the second one becomes first but it's state.Name is now 'Foo' instead of 'Bar'.
I think I'm missing something there with correct creation/removing/displaying components in react.
Edit:
Method used to remove clicked component:
removeCurrentTask(){
this.props.removeTask(this.props.taskObj.id);
}
SingleTask component:
class SingleTask extends Component{
constructor(props) {
super(props);
this.state={
showMenu : false,
afterInit : false,
id: Math.random()*100
}
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu(){
this.setState({showMenu : !this.state.showMenu, afterInit : true});
}
render(){
return(
<MDBRow>
<MDBCard className="singleTaskContainer">
<MDBCardTitle>
<div class="priorityBadge">
</div>
</MDBCardTitle>
<MDBCardBody className="singleTaskBody">
<div className="singleTaskMenuContainer">
<a href="#" onClick={this.toggleMenu}>
<i className="align-middle material-icons">menu</i>
</a>
<div className={classNames('singleTaskMenuButtonsContainer animated',
{'show fadeInRight' : this.state.showMenu},
{'hideElement' : !this.state.showMenu},
{'fadeOutLeft' : !this.state.showMenu && this.state.afterInit})}>
<a
title="Remove task"
onClick={this.props.removeTask.bind(null, this.props.taskObj.id)}
className={
classNames(
'float-right btn-floating btn-smallx waves-effect waves-light listMenuBtn lightRed'
)
}
>
<i className="align-middle material-icons">remove</i>
</a>
<a title="Edit title"
className={classNames('show float-right btn-floating btn-smallx waves-effect waves-light listMenuBtn lightBlue')}
>
<i className="align-middle material-icons">edit</i>
</a>
</div>
</div>
{this.props.taskObj.description}
<br/>
{this.state.id}
</MDBCardBody>
</MDBCard>
</MDBRow>
);
}
}
Below visual representation of error, image on the left is pre-deletion and on the right is post-deletion. While card with "22" was deleted the component itself wasn't deleted, only another object was passed to it.
Just to clarify, the solution was simpler than expected.
In
const showTasks = () => taskList.map((item, index) => (
<SingleTask
taskObj={item}
removeTask ={removeTask}
key = {item.id}
/>
)
)
I was passing map index as a key, when I changed it to {item.id} everything works as expected.
In short, in the statement tasksList.push(<SingleTask taskObj={taskObj} removeTask ={this.removeTask}/>);, removeTask = {this.removeTask} should become removeTask = {() => this.removeTask(taskObj.id)}.
However, I would reconsider the way the methods addTask and showTasks are written. While the way you have written isn't wrong, it is semantically unsound. Here's what I would do:
addTask(taskObj){
let tasksList = this.state.tasksList;
tasksList.push(taskObj);
this.setState({tasksList : tasksList});
}
showTasks(){
return (
this.state.tasksList.map((item, index) => {
return <SingleTask
taskObj={item}
removeTask ={() => this.removeTask(item.id)}/>;
})
);
}
const SingleTask = (task) => {
const { taskObj } = task;
return <div onClick={task.removeTask}>
{ taskObj.title }
</div>
}
// Example class component
class App extends React.Component {
state = {
tasksList: [
{ id: 1, title: "One" },
{ id: 2, title: "Two" },
{ id: 3, title: "Three" },
{ id: 4, title: "Four" }
]
}
addTask = (taskObj) => {
let tasksList = this.state.tasksList;
tasksList.push(taskObj);
this.setState({tasksList : tasksList});
}
showTasks = () => {
return (
this.state.tasksList.map((item, index) => {
return <SingleTask
key={index}
taskObj={item}
removeTask ={() => this.removeTask(item.id)}/>;
})
);
}
removeTask(id) {
this.setState(prevState => ({
tasksList: prevState.tasksList.filter(el => el.id != id )
}));
}
render() {
return (
<div className="App">
<div> {this.showTasks()} </div>
</div>
);
}
}
// Render it
ReactDOM.render(
<App />,
document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Resources