I have this Array
const Routes = [
{
name: "Google Marketing Platform",
roles: ['Devs', 'Adops', ' Planning'],
module: "",
icon: '',
subMenu: [
{
name: "Campaign Manager",
roles: ['Devs', 'Adops', ' Planning'],
module: "GMP",
icon: '',
subMenu: [
{
name: "Campaign Builder",
roles: ['Devs', 'Adops', ' Planning'],
module: "webcb",
icon: '',
subMenu: []
},
{
name: "Reporting",
roles: ['Devs', 'Adops', ' Planning'],
module: "cmReporting",
icon: '',
subMenu: []
}
]
}
]
and i try to render that array on this code
const NavBar = () => {
const [rutas, setRutas] = useState(Routes);
return (
<div className={`navBar__menu ${isNavOpen} `}>
<ul className='navBar__menu-list'>
{rutas.map((data) => {<>
<Link to={`/${data.module}`} className={"navBar__menu-list-subItems"}>
<p className={"navBar__menu-list-items-text"} >{data.name}</p>
</Link>
</>
{
data.subMenu.map((data) => {
<Link to={`/${data.module}`} className={"navBar__menu-list-subItems"}>
<p className={"navBar__menu-list-items-text"} >{data.name}</p>
</Link>
}
)
}
})}
</ul>
</div>
)
}
Elements are not rendering and idk why, becouse i dont have any error on console and i tried with another array and doesnt work either, thanks you for your help!
You're not returning anything from map. You can either change the {} to () like so
rutas.map((data) => (
<>
...everything else
<>
)
or you can use an explicit return
rutas.map((data) => {
return (
<>
...everything else
<>
)
}
Related
I'm new to learning react so I followed this tutorial https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components to create a todo app and then tweaked it to fit the requirements of the project I'm working on. Everything works the way it should except when I delete (complete) things from the associate side, it also deletes it from my main side as well. I understand the general concept of why that's happening (I don't have two separate lists in my code), just not sure how to go about fixing it without removing the filter I have in place. I had tried to implement a separate list for those tasks but just wasn't understanding how to go about it.
Added CodeSandBox for more context: https://codesandbox.io/s/hungry-sky-5f482?file=/src/index.js
Check task items and then view the items you've checked in "Show Associate Tasks." The issue is completing a task on the associate side also completes it on the "Show All Tasks" side.
App.js
const FILTER_MAP = {
All: () => true,
Associate: task => task.checked
};
const FILTER_NAMES = Object.keys(FILTER_MAP);
function App(props) {
const [tasks, setTasks] = useState(props.tasks);
const [filter, setFilter] = useState('All');
function toggleTaskChecked(id) {
const updatedTasks = tasks.map(task => {
if (id === task.id) {
return {...task, checked: !task.checked}
}
return task;
});
setTasks(updatedTasks);
}
function completeTask(id) {
const remainingTasks = tasks.filter(task => id !== task.id);
setTasks(remainingTasks);
}
const taskList = tasks
.filter(FILTER_MAP[filter])
.map(task => (
<Todo
id={task.id}
name={task.name}
checked={task.checked}
key={task.id}
toggleTaskChecked={toggleTaskChecked}
completeTask={completeTask}
/>
));
const filterList = FILTER_NAMES.map(name => (
<FilterButton
key={name}
name={name}
isPressed={name === filter}
setFilter={setFilter}
/>
));
function addTask(name) {
const newTask = { id: "todo-" + nanoid(), name: name, checked: false };
setTasks([...tasks, newTask]);
}
return (
<div className="app">
<h1 className = "tasks-header">Task Tracker</h1>
<Form addTask={addTask}/>
<div className="list-buttons">
{filterList}
</div>
<ul
role="list"
className="todo-list"
aria-labelledby="list-heading"
>
{taskList}
</ul>
</div>
);
}
export default App
Todo.js
export default function Todo(props) {
return (
<li className="todo stack-small">
<div className="c-cb">
<input id={props.id}
type="checkbox"
defaultChecked={props.checked}
onChange={() => props.toggleTaskChecked(props.id)}
/>
<label className="todo-label" htmlFor="todo-0">
{props.name}
</label>
</div>
<div className="btn-group">
<button type="button"
className="complete-button"
onClick={() => props.completeTask(props.id)}
>
Complete
</button>
</div>
</li>
);
}
index.js
const DATA = [
{ id: "todo-0", name: "Brush Teeth", checked: false },
{ id: "todo-1", name: "Make Dinner", checked: false },
{ id: "todo-2", name: "Walk Dog", checked: false },
{ id: "todo-3", name: "Run Reports", checked: false },
{ id: "todo-4", name: "Visit Mom", checked: false },
{ id: "todo-5", name: "Aerobics", checked: false },
{ id: "todo-6", name: "Project", checked: false },
{ id: "todo-7", name: "Lecture", checked: false },
{ id: "todo-8", name: "Have Lunch", checked: false }
];
ReactDOM.render(
<React.StrictMode>
<App tasks={DATA}/>
</React.StrictMode>,
document.getElementById('root')
);
FilterButton.js
function FilterButton(props) {
return (
<button
type="button"
className="toggle-btn"
aria-pressed={props.isPressed}
onClick={() => props.setFilter(props.name)}
>
<span className="visually-hidden">Show </span>
<span>{props.name}</span>
<span className="visually-hidden"> Tasks</span>
</button>
);
}
export default FilterButton;
We have 3 boolean fields: checked, completed, completedAssoc.
{
id: "todo-0",
name: "Brush Teeth",
checked: false,
completed: false,
completedAssoc: false
},
The filters will work as follows:
const FILTER_MAP = {
All: (task) => !task.completed,
Associate: (task) => task.checked && !task.completedAssoc
};
And finally changes in completeTask and addTask:
function completeTask(id) {
const complField = filter === "All" ? "completed" : "completedAssoc";
const updatedTasks = tasks.map((task) =>
id === task.id ? { ...task, [complField]: true } : task
);
setTasks(updatedTasks);
}
function addTask(name) {
const newTask = {
id: "todo-" + nanoid(),
name: name,
checked: false,
completed: false,
completedAssoc: false
};
setTasks([...tasks, newTask]);
}
I am trying to make an authentication based menus in react app.
Menu Data:
const menuItems = {
primaryMenus: [
{ title: 'Messages' },
{ title: 'Register' },
{
subMenus: {
title: 'Account',
menus: [{ title: "Profile" }, { title: "Change Password"}],
},
},
{ title: 'Help' }
],
};
From the above data, I need to build up the menu structure.
The code that I have tried so far
const menuItems = {
primaryMenus: [
{ title: 'Messages' },
{ title: 'Register' },
{
subMenus: {
title: 'Account',
menus: [{ title: "Profile" }, { title: "Change Password"}],
},
},
{ title: 'Help' }
],
};
function App() {
const [ isAuthenticated, setAuthenticated ] = React.useState(false);
return(
<div>
<button onClick={() => {setAuthenticated(!isAuthenticated)}}> {isAuthenticated ? 'Logout' : 'Login'} </button>
<ul className="menu">
{menuItems.primaryMenus.map((menu, i) => {
return (
!menu.subMenus ?
<li key={i}> {menu.title} </li>
:
<li key={i}>
{menu.subMenus.title}
<ul>
{ menu.subMenus.menus.map((submenu, j) => {
return <li key={j}> {submenu.title} </li>
}) }
</ul>
</li>
)
})}
</ul>
<h1> The menu Messages and Help will be there for both logged in user and logged out user </h1>
<br />
<h1> Whereas the Register menu will be available only if user is logged out </h1>
<br />
<h1> My Account menu and its submenus will be available only if user is logged in </h1>
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react#16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
Requirement:
Menu structure for logged in user:
- Messages
- Account
- Profile
- Change Password
- Help
Menu structure for logged out user:
- Messages
- Register
- Help
I can modify the provided json structure (menuItems) as well..
Kindly help me to achieve the above result.
I am new to react, so if anyone could provide me a solution in pure react way of authentication then it would be much more helpful for me..
I would recommend you changed the structure of the array menuItems. For example like this:
const menuItems = [
{ title: 'Messages', whenLoggedIn: true, whenLoggedOut: true },
{ title: 'Help', whenLoggedIn: true, whenLoggedOut: true },
{ title: 'Register', whenLoggedIn: false, whenLoggedOut: true },
{
title: 'Account',
whenLoggedIn: true,
whenLoggedOut: false,
subMenuItems: [{ title: 'Profile' }, { title: 'Change password' }],
},
];
Then you can use them like this:
const keepMenuItem = (menuItem, isAuthenticated) =>
(isAuthenticated && menuItem.whenLoggedIn)
|| (!isAuthenticated && menuItem.whenLoggedOut)
return (
<ul className="menu">
{menuItems.filter(menuItem => keepMenuItem(menuItem, isAuthenticated)
.map(menuItem => (
<li key={menuItem.title}>
{menuItem.title}
{!!menuItem.subMenuItems && (
<ul>
{menuItem.subMenuItems.map(subMenuItem => (
<li key={subMenuItem.title}>{subMenuItem.title}</li>
))}{' '}
</ul>
)}
</li>
))}
</ul>
);
Hello I have doubts on how I can do this in react using useState,
basically i have this menu where i need to map, i basically need a state containing all tags, and with boolean state true or false to know if the current item is active, and i will make it active by clicking on the item, and deactivate it when another item is clicked
that is, only one menu item active at a time
export const SideBarTags = [
{
name: 'Tutoriais',
link: '../tutorials',
icon: faFileAlt,
dropdownItems: null,
active: false,
},
{
name: 'Avisos',
link: '../news',
icon: faNewspaper,
dropdownItems: null,
active: false,
},
{
name: 'Serviços',
link: '../services',
icon: faMeteor,
active: false,
dropdownItems: [
{ name: 'Elo Boost', link: '/eloBost' },
{ name: 'Duo Boost', link: '/duoBoost' },
{ name: 'MD10', link: '/eloBost' },
{ name: 'Coaching', link: '/duoBoost' },
{ name: 'Vitóriais', link: '/duoBoost' },
],
},
{
name: 'Carteira',
link: '../cartcredit',
icon: faWallet,
active: false,
dropdownItems: [
{ name: 'Histórico', link: '/history' },
{ name: 'Adicionar Crédito', link: '/add' },
],
},
];
and my TSX:
const MenuTags: React.FC<Hamburguer> = ({ isOpen }) => {
const [menuTags, setMenuTags] = useState(SideBarTags.map());
return (
<DashMenu open={isOpen}>
<MenuItem /> //(this is my tag <li>
</DashMenu>
);
};
const MenuItem: React.FC = () => {
return (
<ListItem>
<ListWrap
>
<a>
<FontAwesomeIcon
className="icon-li"
icon={icon}
size={isOpen ? 'lg' : 'lg'}
fixedWidth
color="white"
/>
<span
className="li-name"
>
{name}
</span>
</a>
</ListItem>
);
};
Component logic if you wanted to map the menu items with the active item
const [menuItems, setMenuItems] = useState(SideBarTags);
const clickHandler = name => () => {
setMenuItems(items =>
items.map(item => ({
...item,
active: item.name === name
}))
);
};
...
{menuItems.map(item => (
<li
key={item.name}
className={item.active ? "active" : ""}
onClick={clickHandler(item.name)}
>
{item.name}
</li>
))}
CSS
.active {
// could be whatever style you need
color: red;
}
Super simplified version of what I did in a past project:
const MenuTags = () => {
const [selectedLink, setSelectedLink] = useState(null)
return (
<ul>
{SideBarTags.map((obj) => (
<li className={`${selectedLink === obj.name ? 'link--selected' : ''}`}>
<a
onClick={() => {
setSelectedLink(obj.name)
}}
href={obj.link}
>
{obj.name}
</a>
</li>
))}
</ul>
)
}
Use CSS to open and close the menu items, by having a class such as 'link--selected' added to an element you can just show that item.
I am having issues on even trying to get started with doing pagination without the use of any packages. I am pulling data from a JSON file that contains about 30-32 quotes. I need 15 quotes per page to be displayed and have no idea how to even do that using React. So far what I have is all the quotes being displayed by default. I have three buttons, each filters through the JSON to provide quotes by the theme of the quote which is displayed by the button. This is how far I got:
class App extends Component {
constructor(props) {
super(props);
this.state ={
results: quotes,
search: ""
}
}
gameFilterClick = event => {
event.preventDefault();
const games = [];
for(let i = 0; i < quotes.length; i++){
if (quotes[i].theme === "games"){
games.push(quotes[i])
}
}
this.setState({results: games})
}
movieFilterClick = event => {
event.preventDefault();
console.log('blah!!')
const movies = [];
for(let i =0; i < quotes.length; i++){
if(quotes[i].theme === 'movies'){
movies.push(quotes[i])
}
}
this.setState({results: movies})
}
allButtonClick = event => {
this.setState({results: quotes})
}
quoteSearch = query => {
let search = quotes.map
}
render() {
return (
<div className="App">
<h1>Quotes</h1>
<Search />
<div id='buttons'>
Filters:
<button onClick={this.allButtonClick}>All Quotes</button>
<button onClick={this.gameFilterClick}>Games</button>
<button onClick={this.movieFilterClick}>Movies</button>
</div>
<div id='resultsDiv'>
<Results
results={this.state.results}
/>
</div>
</div>
);
}
}
export default App;
I would recommend using react-bootstrap for this. You'll need to install two packages (they use to come in one, but now pagination package is separated):
react-bootstrap-table-next
react-bootstrap-table2-paginator
So, let's install them:
npm i --save react-bootstrap-table-next
npm i react-bootstrap-table2-paginator
And here goes a simple example of implementation:
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// Let's imagine this is your JSON data
const yourJsonData = [{id: 1, author: "David Goggins", quote: "Life goes on"},
{ id: 2, author: "Robert Green", quote: "yes it does"}]:
// Here we define your columns
const columns = [{
dataField: 'author',
text: 'AUTHOR'
}, {
dataField: 'quote',
text: 'QUOTE'
}];
// Give it an option to show all quotes
let allQuotes = Number(yourJsonData.length);
// Set all of the major pagination options. You can reduce them if you want less
const options = {
paginationSize: 15,
pageStartIndex: 0,
firstPageText: 'First',
prePageText: 'Back',
nextPageText: 'Next',
lastPageText: 'Last',
nextPageTitle: 'First page',
prePageTitle: 'Pre page',
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
sizePerPageList: [{
text: 'show 15', value: 15
}, {
text: 'show 30', value: 30
}, {
text: 'Show all', value: allQuotes
}]
};
... and then somewhere later in your code where you want to display the table with pagination you just insert this:
<BootstrapTable
keyField='rowNumber'
data={ yourJsonData }
columns={ columns }
pagination={ paginationFactory(options) } />
I hope this solves your problem.
I've simplified your filtering logic and added client side pagination. Check out this simple working example (i've set item per page to 3, you can add more data and change it to 15 const QUOTES_PER_PAGE = <number of quotes per page>;)
const QUOTES_PER_PAGE = 3;
const Quote = ({text}) => <li>{text}</li>;
const Pagination = ({pages, goTo}) => (
<div>
{pages.map((p, i) => (
<button key={i} onClick={goTo} value={i}>{i+1}</button>
))}
</div>
)
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 0,
pagedQuoutes: this.divideQuoutesIntoPages(props.quotes)
};
}
divideQuoutesIntoPages = (quotes => {
const pagedQuotes = [];
[...Array(Math.ceil(quotes.length/QUOTES_PER_PAGE))].forEach((q, i) => {
pagedQuotes.push(quotes.slice(0 + QUOTES_PER_PAGE*i, QUOTES_PER_PAGE + QUOTES_PER_PAGE*i))
})
return pagedQuotes;
})
filterQuoutes = (evt) => {
const filterValue = evt.target.value;
const filteredQuoutes = this.props.quotes.filter(q => !filterValue || q.theme === filterValue);
this.setState({
pagedQuoutes: this.divideQuoutesIntoPages(filteredQuoutes)
})
}
goToPage = (evt) => {
this.setState({
page: evt.target.value
})
}
render() {
return (
<div>
<h1>Quotes</h1>
<div>
Filters:
<button onClick={this.filterQuoutes}>All Quotes</button>
<button onClick={this.filterQuoutes} value="games">Games</button>
<button onClick={this.filterQuoutes} value="movies">Movies</button>
</div>
{this.state.pagedQuoutes[this.state.page]
.map(q => (
<ul>
<Quote {...q} />
</ul>
))}
<Pagination pages={this.state.pagedQuoutes} goTo={this.goToPage} />
</div>
);
}
}
const exampleQuotes = [{
theme: 'games',
text: 'games q1'
}, {
theme: 'games',
text: 'games q2'
}, {
theme: 'games',
text: 'games q3'
}, {
theme: 'games',
text: 'games q4'
}, {
theme: 'games',
text: 'games q5'
}, {
theme: 'movies',
text: 'movies q1'
}, {
theme: 'movies',
text: 'movies q2'
}, {
theme: 'movies',
text: 'movies q3'
}]
ReactDOM.render(<App quotes={exampleQuotes} />, document.getElementById("el"))
<div id="el"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
I created an array which contains objects and I want to loop through it using the map function and return the items inside that array. For some reason, the items are not returning. I don't know what I'm doing wrong.
const SideNavItem = () => {
const items = [
{
icon: 'home',
link: '/',
name: 'Home',
},
{
icon: 'apple',
link: '/',
name: 'About',
},
{
icon: 'angelist',
link: '/',
name: 'Support',
},
];
const itemlisting = () => {
return items.map((item, i) => {
return (
<div key={i}>
<Link to={item.link}>
<FontAwesome name={item.icon} />
{item.name}
</Link>
</div>
);
});
};
return <div>{itemlisting}</div>;
};
export default SideNavItem;
Gotcha...!
Solution1: you have defined itemlisting as a function. You have defined it but not called it in your return statement.
So you have to have your return statement as below.
return(
<div>
{itemlisting()}
</div>
)
Solution 2: (OR) you could change your itemlisting as below. It doesn't need to be a function. Just an array.
const itemlisting = items.map((item, i) => {
return (
<div key={i}>
<Link to={item.link}>
<FontAwesome name={item.icon} />
{item.name}
</Link>
</div>
);
});