React horizontal scroll componet doesn't visible - javascript

I'm trying to implement react horizontal scroll using React horizontal scrolling menu library, but when I use this component in my react app, it shows nothing and I am also not getting any error message.
Here is the code of that component:
import React, { useState } from "react";
import { ScrollMenu } from "react-horizontal-scrolling-menu";
// list of items
const list = [
{ name: "item1" },
{ name: "item2" },
{ name: "item3" },
{ name: "item4" },
{ name: "item5" },
{ name: "item6" },
{ name: "item7" },
{ name: "item8" },
{ name: "item9" },
];
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return <div className="menu-item text-black">{text}</div>;
};
// All items component
// Important! add unique key
export const Menu = (list) =>
list.map((el) => {
const { name } = el;
return <MenuItem text={name} key={name} />;
});
const Arrow = ({ text, className }) => {
return <div className={className}>{text}</div>;
};
const ArrowLeft = Arrow({ text: "<", className: "arrow-prev" });
const ArrowRight = Arrow({ text: ">", className: "arrow-next" });
const AvataaarsScroll = () => {
const [selected, setSelected] = useState(0);
const onSelect = (key) => {
setSelected(key);
};
// Create menu from items
const menu = Menu(list, selected);
return (
<div className="App">
<ScrollMenu
data={menu}
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={onSelect}
/>
</div>
);
};
export default AvataaarsScroll;
Anyone please help me with this.

You are sending the menu items to the ScrollMenu through the property named data, but you need to send them as children elements:
<div className="App">
<ScrollMenu
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={onSelect}
>
{menu}
</ScrollMenu>
</div>
...or...
<ScrollMenu
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={onSelect}
children={menu}
/>

Related

REACT-SELECT defaultValue in CustomDropdown not working

I want the default value of my dropdown to be defaultValue={item.taste} (value from match.json) but it's not working... (go to /menu/Menu1 and Pea Soup)
import Select from "react-select";
export default function CustomDropdown({ style, options, defaultValue }) {
return (
<div style={style}>
<Select options={options} defaultValue={defaultValue} />
</div>
);
}
MenuItemDisplay:
export default function MenuItemDisplay() {
const { menuId, itemId } = useParams();
const { match } = JsonData;
const matchData = match.find((el) => el._id_menu === menuId)?._ids ?? [];
const item = matchData.find((el) => el._id === itemId);
const styles = {
select: {
width: "100%",
maxWidth: 150
}
};
const TASTE = [
{ label: "Good", value: "Good" },
{ label: "Medium", value: "Medium" },
{ label: "Bad", value: "Bad" }
];
...
return (
<>
<div className="TextStyle">
{"Taste "}
<CustomDropdown
style={styles.select}
options={TASTE}
defaultValue={item.taste}
//The default value is not working only if it's
//TASTE[0]
/>
</div>
...
</>
);
}
Here the link for the code
As defaultValue you need to pass one of the objects of the TASTE array. You can do this:
<CustomDropdown
style={styles.select}
options={TASTE}
defaultValue={TASTE.find(t => t.label === item.taste)}
/>

Why can't property map be read?

I am trying to iterate through an array of objects to display all items of a certain name. For some reason my this.props.list.items cannot be read. Any help would be greatly appreciated.
The code for item.js
import React from "react";
class Item extends React.Component{
render() {
return(
<div>{this.props.list.items}</div>
)
}
}
export default Item
The code for horizontalscroll.js
import React from 'react';
import ScrollMenu from 'react-horizontal-scrolling-menu';
import './horizontalscroll.css';
import Item from './Item';
// list of items
const list = [
{
name: "Brands",
items: ["1", "2", "3"]
},
{
name: "Films",
items: ["f1", "f2", "f3"]
},
{
name: "Holiday Destination",
items: ["f1", "f2", "f3"]
}
];
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return (
<div
className="menu-item"
>
{text}
</div>
);
};
// All items component
// Important! add unique key
export const Menu = (list) => list.map(el => {
const { name } = el;
return (
<MenuItem
text={name}
key={name}
/>
);
});
const Arrow = ({ text, className }) => {
return (
<div
className={className}
>{text}</div>
);
};
const ArrowLeft = Arrow({ text: '<', className: 'arrow-prev' });
const ArrowRight = Arrow({ text: '>', className: 'arrow-next' });
class HorizantScroller extends React.Component {
state = {
selected: 0
};
onSelect = key => {
this.setState({ selected: key });
}
render() {
const { selected } = this.state;
// Create menu from items
const menu = Menu(list, selected);
return (
<div className="HorizantScroller">
<ScrollMenu
data={menu}
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={this.onSelect}
/>
<div>{this.props.items.map((item) => {
return <Item item={item}/>
})}
</div>
</div>
);
}
}
export default HorizantScroller;
Inside Item, you should access it like this
<div>{this.props.item}</div>
Because when rendering Item, you did <Item item={item}/>

Why does my React component display incorrect data when filtering by values controlled by useState()?

I have a list of objects that I'd like to pass to a map function which passes each object as props to a component to be rendered.
I have a menu and clicking each item calls setActiveItem() updating activeItem which is being managed by useState hook.
I'm trying to filter the list of objects based on this activeItem value. I've created a base case trying to replicate the problem but my base case works flawlessly though it'll at least clarify what I'm trying to do so here it is:
import React, { useState } from 'react';
import { Menu } from 'semantic-ui-react';
const [ALL, NUMBER, LETTER] = ['All', 'Number', 'Letter'];
const data = [
{
tags: [ALL, NUMBER],
value: '1'
},
{
tags: [ALL, LETTER],
value: 'a'
},
{
tags: [ALL, NUMBER],
value: '2'
},
{
tags: [ALL, LETTER],
value: 'b'
},
{
tags: [ALL, NUMBER],
value: '3'
},
{
tags: [ALL, LETTER],
value: 'c'
},
{
tags: [ALL, NUMBER],
value: '4'
},
{
tags: [ALL, LETTER],
value: 'd'
}
];
const renderData = (allValues, filterTag) => {
let filteredList = allValues.filter(val => {
return val['tags'].includes(filterTag);
});
return (
<div>
{filteredList.map(object_ => {
return object_.value;
})}
</div>
);
};
const BaseCase = props => {
const [activeItem, setActiveItem] = useState(ALL);
return (
<div>
<Menu inverted stackable fluid widths={4}>
<Menu.Item
name={ALL}
active={activeItem === ALL}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={NUMBER}
active={activeItem === NUMBER}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={LETTER}
active={activeItem === LETTER}
onClick={(e, { name }) => setActiveItem(name)}
/>
</Menu>
<div>{renderData(data, activeItem)}</div>
</div>
);
};
export default BaseCase;
Clicking number only shows numbers and everything else works as expected. Now for my component that isn't working. I have my data in a separate file like so:
import { BASH, DATA_SCIENCE, WEB_DEV, ALL } from '../constants';
const data = [
{
tags: [ALL],
title: 'Concussion App for Athletes',
.
.
.
},
{
tags: [DATA_SCIENCE, ALL],
title: 'Deep Learning: Exploring Car Value with an ANN',
...
},
.
.
.
];
export default data;
Here's my component. There's some commented out code that I tried but that also gave incorrect components being displayed.
import React, { useState } from 'react';
import ProjectCardContainer from '../../containers/ProjectCardContainer';
import { Menu } from 'semantic-ui-react';
import { ALL, BASH, DATA_SCIENCE, WEB_DEV } from './constants';
import data from './project_data';
import './Projects.scss';
const styles = {
container: {
display: 'flex',
justifyContent: 'space-around'
},
columns: {
display: 'flex',
flexDirection: 'column',
marginTop: '11px'
}
};
const renderColumn = (projectList, filterTag) => {
let projects = projectList.filter(proj => {
return proj['tags'].includes(filterTag);
});
return (
<div style={styles.columns}>
{projects.map(project => {
return <ProjectCardContainer project={project} />;
})}
</div>
);
};
const Projects = () => {
const [activeItem, setActiveItem] = useState(ALL);
// const [, updateState] = React.useState();
// const forceUpdate = useCallback(() => updateState({}), []);
// useEffect(() => {
// setTimeout(forceUpdate, 100);
// }, [activeItem]);
return (
<div>
<div className='second-nav-container'>
<Menu inverted stackable fluid widths={4}>
<Menu.Item
name={ALL}
active={activeItem === ALL}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={WEB_DEV}
active={activeItem === WEB_DEV}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={DATA_SCIENCE}
active={activeItem === DATA_SCIENCE}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={BASH}
active={activeItem === BASH}
onClick={(e, { name }) => setActiveItem(name)}
/>
</Menu>
</div>
<div style={styles.container}>{renderColumn(data, activeItem)}</div>
</div>
);
};
export default Projects;
Basically the rendered list of components usually isn't correct except maybe when the page is refreshed and the default value from useState() is used. Selecting from the menu doesn't show the components of the correct category.
I believe the problem is that the render function is getting called before activeItem is updated but I'm not sure how to work around that issue. I'm somewhat new to using hooks but this seems like a problem that must come up a lot.
Anyone Have any ideas how I can use a menu like this to filter data then only show specific components based on filtered data?
The problem in the end was I wasn't providing a unique key while rendering lists of components. The solution is to provide a unique key like so:
const renderColumn = (projectList, filterTag) => {
let projects = projectList.filter(proj => {
return proj['tags'].includes(filterTag);
});
return (
<div style={styles.columns}>
{projects.map(project => {
return <ProjectCardContainer key={project.title} project={project} />;
})}
</div>
);
};
In my case I know the titles will be unique so this works.
I don't think we need to mess around too much with complicated state management. I updated the base case to meet your needs:
Constants.js:
export const [ALL, DATA_SCIENCE, WEB_DEV, BASH] = ['All', 'DATA_SCIENCE', 'WEB_DEV', 'BASH'];
data.js:
import {ALL, DATA_SCIENCE, WEB_DEV, BASH} from './Constants';
const data = [
{
tags: [ALL],
title: 'Concussion App for Athletes',
},
{
tags: [DATA_SCIENCE, ALL],
title: 'Deep Learning: Exploring Car Value with an ANN',
},
{
tags: [BASH, ALL],
title: 'Bash 101'
},
{
tags: [WEB_DEV, ALL],
title: 'Web Development Book'
},
{
tags: [WEB_DEV, ALL],
title: 'Fundamentals of web design'
}
]
export default {data};
BaseCase.js:
import React, { useState } from 'react';
import { Menu } from 'semantic-ui-react';
import data from './data';
import {ALL, DATA_SCIENCE, WEB_DEV, BASH} from './Constants';
const renderData = (allValues, filterTag) => {
let filteredList = Object.values(allValues.data).filter(val => {
return val['tags'].includes(filterTag);
});
return (
<div>
{filteredList.map(object_ => {
return <p>{object_.title}</p>;
})}
</div>
);
};
const BaseCase = props => {
const [activeItem, setActiveItem] = useState(ALL);
const newData = data;
return (
<div>
<Menu inverted stackable fluid widths={4}>
<Menu.Item
name={ALL}
active={activeItem === ALL}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={DATA_SCIENCE}
active={activeItem === DATA_SCIENCE}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={WEB_DEV}
active={activeItem === WEB_DEV}
onClick={(e, { name }) => setActiveItem(name)}
/>
<Menu.Item
name={BASH}
active={activeItem === BASH}
onClick={(e, { name }) => setActiveItem(name)}
/>
</Menu>
<div>{renderData(newData, activeItem)}</div>
</div>
);
};
export default BaseCase;
At return <p>{object_.title}</p>; render out your component like <ProjectCardContainer project={object_} />

Toggling a classname for one button in a list of buttons

I have a list of buttons and I'm trying to toggle the classname when one is clicked. So that only when I click on a specific button is highlighted. I have a TagList component that looks like this:
const Tags = ({tags, onTagClick}) => {
return (
<div className="tags-container">
{ tags.map(tag => {
return (
<span
key={tag.name}
className="tag"
onClick={() => onTagClick(tag)}
>
{tag.name} | {tag.numberOfCourses}
</span>
)
})
}
</div>
)
}
And this is found in the parent component:
onTagClick = (tag) => {
this.filterCourses(tag)
}
render() {
const { tags, courses } = this.state
return (
<div>
<h1> Course Catalog Component</h1>
<Tags tags={tags} onTagClick={this.onTagClick} />
<Courses courses={courses} />
</div>
)
}
I know how I could toggle the class for a single button but I'm a little confused when it comes to a list of buttons. How can I toggle one specifically from a list of buttons? Am I going to need a seperate Tag component and add state to that one component?
EDIT:
This is what my state currently looks like:
constructor(props) {
super(props)
this.state = {
tags: this.sortedTags(),
courses: courses
}
}
And this is what filterCourses looks like:
filterCourses = (tag) => {
this.setState({
courses: courses.filter(course => course.tags.includes(tag.name))
})
}
To start, you would want to give each tag object you're working with a selected property. That will make it easier for you to toggle the class. During the rendering of that markup.
Here is the working sandbox: https://codesandbox.io/s/stupefied-cartwright-6zpxk
Tags.js
import React from "react";
const Tags = ({ tags, onTagClick }) => {
return (
<div className="tags-container">
{tags.map(tag => {
return (
<div
key={tag.name}
className={tag.selected ? "tag selected" : "tag"}
onClick={() => onTagClick(tag)}
>
{tag.name} | {tag.numberOfCourses}
</div>
);
})}
</div>
);
};
export default Tags;
Then in the Parent component, we simply toggle the selected prop (True/False) when the tag is clicked. That will update the tags-array and it gets passed back down to the Child-component which now has the new selected values.
Parent Component
import React from "react";
import ReactDOM from "react-dom";
import Tags from "./Tags";
import Courses from "./Courses";
import "./styles.css";
class App extends React.Component {
state = {
tags: [
{ id: 1, name: "math", numberOfCourses: 2, selected: false },
{ id: 2, name: "english", numberOfCourses: 2, selected: false },
{ id: 3, name: "engineering", numberOfCourses: 2, selected: false }
],
courses: [
{ name: "Math1a", tag: "math" },
{ name: "Math2a", tag: "math" },
{ name: "English100", tag: "english" },
{ name: "English200", tag: "english" },
{ name: "Engineering101", tag: "engineering" }
],
sortedCourses: []
};
onTagClick = tag => {
const tagsClone = JSON.parse(JSON.stringify(this.state.tags));
let foundIndex = tagsClone.findIndex(tagClone => tagClone.id == tag.id);
tagsClone[foundIndex].selected = !tagsClone[foundIndex].selected;
this.setState(
{
tags: tagsClone
},
() => this.filterCourses()
);
};
filterCourses = () => {
const { tags, courses } = this.state;
const selectedTags = tags.filter(tag => tag.selected).map(tag => tag.name);
const resortedCourses = courses.filter(course => {
return selectedTags.includes(course.tag);
});
this.setState({
sortedCourses: resortedCourses
});
};
render() {
const { tags, sortedCourses, courses } = this.state;
return (
<div>
<h1> Course Catalog Component</h1>
<Tags tags={tags} onTagClick={this.onTagClick} />
<Courses courses={!sortedCourses.length ? courses : sortedCourses} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Passing onselect value from menu component to another component reactjs

I am new to react and I've been trying to achieve a function that I am not sure of, I have a component that renders JSON file and shows products named 'product list', another component named 'person' which is used to show product items, both are working fine, but the third component called menucat includes the scrolling menu from https://www.npmjs.com/package/react-horizontal-scrolling-menu, the onselect function of the menu component returns an id number on selection, I want to pass that number inside the mapping function within the productlist.
Product list
import React from "react";
import Person from "./Person";MenuCat";
import MenuCat, {a, onSelect, selected} from "../components/
class ProductList extends React.Component {
state = {
error: null,
isLoaded: false,
items: []
};
componentDidMount() {
fetch("items.json")
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
items: result
});
},
error => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return (
<div>
Error:{" "}
{error.message }
{console.log("check 1:", items)}
</div>
);
} else if (!isLoaded) {
return (
<div>
<img
src="loading.gif"
alt="loading"
height="100"
/>
</div>
);
} else {
return (
<div>
<MenuCat />
<div className="row">
{items.children[0].children.map(item => (
<Person
className="person"
Key={item.name}
Title={item.name}
imgSrc={item.image_url}
>
{item.base_price}
</Person>
))}
</div>
</div>
);
}
}
}
and the menuCat component looks like this
import React, { Component } from "react";
import ScrollMenu from "react-horizontal-scrolling-menu";
import "../menu.css";
// list of items
const list = [
{ name: "category1" , id : 0},
{ name: "category2" , id : 1},
{ name: "category3" , id : 2},
{ name: "category4" , id : 3},
{ name: "category5" , id : 4},
{ name: "category6" , id : 5},
{ name: "category7" , id : 6},
];
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return <div className="menu-item">{text}</div>;
};
// All items component
// Important! add unique key
export const Menu = list =>
list.map(el => {
const { name } = el;
const { id } = el;
return <MenuItem text={name} key={id} />;
});
const Arrow = ({ text, className }) => {
return <div className={className}>{text}</div>;
};
const ArrowLeft = Arrow({ text: "<", className: "arrow-prev" });
const ArrowRight = Arrow({ text: ">", className: "arrow-next" });
export class Menucat extends Component {
state = {
selected: "0"
};
onSelect = key => {
console.log(`onSelect: ${key}`);
this.setState({ selected: key});
};
render() {
const { selected } = this.state;
// Create menu from items
const menu = Menu(list, selected);
return (
<div className="App">
<ScrollMenu
data={menu}
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={this.onSelect}
/>
</div>
);
}
}
export default Menucat;
I want the id generated from onselect function to be added instead of 0 in
{items.children[0].children.map(item => (
so that whenever the user clicks on a category item, the id of that category goes to the mapping function which will do the rest. I am aware that the category list is hardcoded, for now, I just want this communication between the components to happen, I want to pass the id from the menucat component to a something like a variable in product list that can go instead of the zero like {items.children[selected].children.map(item => (
you'll want to add an 'onSelect' prop to MenuCat to pass through the ScrollMenu's onSelect results, then a state value in ProductList to store the selected key. something like this:
ProductList
import React from "react";
import Person from "./Person";MenuCat";
import MenuCat, {a, onSelect, selected} from "../components/
class ProductList extends React.Component {
state = {
error: null,
isLoaded: false,
items: [],
selected: 0,
};
componentDidMount() {
fetch("items.json")
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
items: result
});
},
error => {
this.setState({
isLoaded: true,
error
});
}
);
}
constructor(props) {
super(props);
this.onSelect = this.onSelect.bind(this);
}
onSelect(key) {
this.setState({selected: key});
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return (
<div>
Error:{" "}
{error.message }
{console.log("check 1:", items)}
</div>
);
} else if (!isLoaded) {
return (
<div>
<img
src="loading.gif"
alt="loading"
height="100"
/>
</div>
);
} else {
return (
<div>
<MenuCat onSelect={this.onSelect} />
<div className="row">
{items.children[this.state.selected].children.map(item => (
<Person
className="person"
Key={item.name}
Title={item.name}
imgSrc={item.image_url}
>
{item.base_price}
</Person>
))}
</div>
</div>
);
}
}
}
and MenuCat like
import React, { Component } from "react";
import ScrollMenu from "react-horizontal-scrolling-menu";
import "../menu.css";
// list of items
const list = [
{ name: "category1" , id : 0},
{ name: "category2" , id : 1},
{ name: "category3" , id : 2},
{ name: "category4" , id : 3},
{ name: "category5" , id : 4},
{ name: "category6" , id : 5},
{ name: "category7" , id : 6},
];
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return <div className="menu-item">{text}</div>;
};
// All items component
// Important! add unique key
export const Menu = list =>
list.map(el => {
const { name } = el;
const { id } = el;
return <MenuItem text={name} key={id} />;
});
const Arrow = ({ text, className }) => {
return <div className={className}>{text}</div>;
};
const ArrowLeft = Arrow({ text: "<", className: "arrow-prev" });
const ArrowRight = Arrow({ text: ">", className: "arrow-next" });
export class Menucat extends Component {
state = {
selected: "0"
};
onSelect = key => {
console.log(`onSelect: ${key}`);
this.setState({ selected: key});
this.props.onSelect(key);
};
render() {
const { selected } = this.state;
// Create menu from items
const menu = Menu(list, selected);
return (
<div className="App">
<ScrollMenu
data={menu}
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
selected={selected}
onSelect={this.onSelect}
/>
</div>
);
}
}
export default Menucat;
you pass an 'onSelect' function to menucat, menucat calls it when the item is selected, and back in ProductList, its 'onSelect' function is then run, setting state which can then be used in your item selection.
make sense?

Categories