I'm new to react and trying to create a ecommerce website. For the navigation and category items, I have used a endpoint url.
http://149.129.128.3:3737/search/resources/store/1/categoryview/#top?depthAndLimit=-1,-1,-1,-1
and the screenshot of response is given below
The problem which I'm facing is that when I click on the categories like Apparel, Electronics, upto the first level of category, I'm able to render it.
But under that subsection, there is another category, which I'm not able to render(E.g under Girls there is shoes, pants etc) and the code is given below
topNavigation.js
import React, { Component } from 'react';
import axios from 'axios';
import SubMenu from './subMenu';
class Navigation extends Component {
state = {
mainCategory: []
}
componentDidMount() {
axios.get('http://localhost:3030/topCategory')
.then(res => {
console.log(res.data.express);
this.setState({
mainCategory: res.data.express.catalogGroupView
})
})
}
render() {
const { mainCategory } = this.state;
return mainCategory.map(navList => {
return (
<ul className="header">
<li key={navList.uniqueID}>
<a className="dropbtn ">
{navList.name}
<ul className="dropdown-content">
<SubMenu below={navList.catalogGroupView}/>
</ul>
</a>
</li>
</ul>
)
})
}
}
export default Navigation;
subMenu.js
import React, { Component } from 'react';
import SubListMenu from './subListMenu';
class SubMenu extends Component {
render() {
const {below} = this.props;
return below.map(sub => {
return (
<div>
<li key={sub.uniqueID}> <a>{sub.name}</a></li>
<SubListMenu subBelow={this.props}/>
</div>
)
})
}
}
export default SubMenu;
subListMenu.js
import React, { Component } from 'react';
class SubListMenu extends Component {
render() {
const {subBelow} = this.props;
return subBelow.map(sub => {
return (
<li key={sub.uniqueID}> <a>{sub.name}</a></li>
)
})
}
}
export default SubListMenu;
Can someone please help me on this. I'm not able to figure it out. I don't know where my code is getting wrong. Or if somebody could atleast give an insight how to proceed further.
Try to change this line:
<SubListMenu subBelow={this.props}/>
to this:
<SubListMenu {...this.props}/>
or to this
<SubListMenu subBelow={this.props.below}/>
You are passing the whole props object to subBelow, so you are trying to map through an object, but Object.prototype.map is not a function.
Related
i have a random list of 10 dogs and fetching it from api https://dog.ceo/api/breeds/image/random/10 and with every refresh i get another 10 dogs list so my question is how do i make favorite list out of it and show it on another page. I dont want to use Localstorage or redux or context api.
DogHome.js
import "bootstrap/dist/css/bootstrap.min.css";
import "../../Pages/Pages.css";
import DogList from "../Dog/DogList";
import React, { Component } from "react";
class DogHome extends Component {
constructor(props) {
super(props);
this.state = {
dogs: [],
};
}
async componentDidMount() {
try {
const url = "https://dog.ceo/api/breeds/image/random/10";
const response = await fetch(url);
const data = await response.json();
this.setState({ dogs: data.message });
} catch (e) {
console.error(e);
}
}
render() {
return (
<div className="home">
<DogList dogs={this.state.dogs} />
</div>
);
}
}
export default DogHome;
DogList.js
import React from "react";
import Dog from "./Dog";
import "../../Pages/Pages.css";
const DogList = (props) => {
const dogsArray = props.dogs.map((dogURL, index) => {
return <Dog key={index} url={dogURL} />;
});
return (
<>
<div className="doglist">{dogsArray}</div>
</>
);
};
export default DogList;
and lastly here i have a favorite button in every dog image which i want to make favorite on click.
Dog.js
import React from "react";
import { Button } from "react-bootstrap";
import "../../Pages/Pages.css";
const Dog = (props) => {
return (
<div id="child">
<img
style={{ width: 300, height: 300 }}
src={props.url}
alt="ten dogs list"
/>
<Button >Favorite</Button>
</div>
);
};
export default Dog;
You say don't want to use those APIs but you need a method to store favorites. How are you going to decide which are the favorites? How else are you planning to store the values of favorite dogs? You can use a database or a flat file. But you might as well take advantage of some of the React state management if that's your goal.
I am using React to fetch an API to display data after clicking on buttons. Each button is a category, once clicked it shows cards for that category only.
I would like to know how to communicate between components to have one component with the buttons and one component with the data from one category without having to call the API twice and just passing the value for the category.
The value of the button is a dynamic value passed inside the API call and I am not sure how to communicate between the buttons components and the display of data.
Any help would be greatly appreciated
The routing component:
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import Navbar from '../components/NavBar/NavBar'
import HomeButtons from './HomeButtons/HomeButtons';
import CardsCategory from './CardsCategory/CardsCategory';
import CardsProps from './CardsCategory/CardsProps'
class Routing extends Component {
render() {
return (
<div>
<Route path="/" component={Navbar} />
<Route exact path="/" component={HomeButtons} />
<Route exact path="/cards" component={CardsProps} />
</div>
)
}
}
export default Routing
The buttons component :
import React, { Component } from 'react'
import axios from 'axios';
import './HomeButtons.css';
import ButtonCategory from '../../components/ButtonCategory/ButtonCategory'
class HomeButtons extends Component {
handleClick = (buttonValue) => {
// only 3 first letters of the button to match category in the API:
buttonValue = buttonValue.slice(0, 3).toLowerCase();
axios.get('http://api.nobelprize.org/2.0/nobelPrizes?sort=desc&nobelPrizeCategory=' + buttonValue + '&format=json&csvLang=en')
.then(res => {
const categoryData = res.data.nobelPrizes;
// console.log("CATEGORY", categoryData?.category?.en)
this.setState({
category: buttonValue
})
}).
catch(err => console.log(err))
};
render() {
const allCategoriesButtons = ["Physics", "Chemistry", "Medicine", "Literature", "Peace", "Economics"];
const allCatMap = allCategoriesButtons.map(button =>
< ButtonCategory
key={button.toString()}
value={button}
name={button}
onClick={e => this.handleClick(e.target.value)}
/>
)
return (
<div>
<div className="container__section">
{allCatMap}
</div >
</div>
)
}
}
export default HomeButtons;
The cards data component with a hard coded category in the API call :
import axios from 'axios';
import WinnerCard from '../../components/WinnerCard/WinnerCard'
class Cards extends Component {
state = {
allCards: []
}
componentDidMount() {
axios.get('http://api.nobelprize.org/2.0/nobelPrizes?sort=desc&nobelPrizeCategory=eco&format=json&csvLang=en')
.then(res => {
const categoryData = res.data.nobelPrizes;
this.setState({
allCards: categoryData,
// category: buttonValue
})
}).
catch(err => console.log(err))
};
render() {
const cards = this.state.allCards.map((card) => {
return <WinnerCard
key={card.id}
awardYear={card.awardYear}
category={card.category.en}
name={card.laureates[0].knownName?.en}
motivation={card.laureates[0].motivation?.en}
/>
})
return (
<div>
{cards}
</div>
)
}
}
export default Cards
Communication between SIBLING components can be achieved using FBEMITTER but that would IMHO make the structure a little confusing with multiple components interacting at multiple levels.
However, it feels like you might want to take a different approach something like below, just a thought.
Since you have routes defined for the cards tab, I think it's best, if you could send the category as a parameter in the URL itself, something like /cards/:category_name.
Changes go about like this
class Routing extends Component {
render() {
return (
<div>
<Route path="/" component={Navbar} />
<Route exact path="/" component={HomeButtons} />
<Route exact path="/cards/:category_name" component={Cards} />
</div>
)
}
}
export default Routing
HomeButtons
Here, instead of setting the state inside the axios then, you can just re route your application to /cards/:category_name
handleClick = (buttonValue) => {
// only 3 first letters of the button to match category in the API:
buttonValue = buttonValue.slice(0, 3).toLowerCase();
axios.get('http://api.nobelprize.org/2.0/nobelPrizes?sort=desc&nobelPrizeCategory=' + buttonValue + '&format=json&csvLang=en')
.then(res => {
---------------------------------------
Change the route to /cards/<buttonValue>
---------------------------------------
}).
catch(err => console.log(err))
};
Cards
class Cards extends Component {
...
componentDidMount() {
axios.get('http://api.nobelprize.org/2.0/nobelPrizes?sort=desc&nobelPrizeCategory=eco&format=json&csvLang=en')
.then(res => {
const categoryData = res.data.nobelPrizes;
this.setState({
allCards: categoryData,
category: <fetch category from the API that your router provides>
})
}).
catch(err => console.log(err))
};
render() {
...
}
}
export default Cards
im having a real hard time learning react and I can't quite understand how to solve this problem. I have Tournaments.js which reads tournament names from an API and displays them as clickable elements with a reference to templates.js in which I would like to simply display the name of the element that was clicked.
Tournaments.js:
import React, { Component } from "react";
const API = 'http://localhost:8080/api/tournaments';
class Tournaments extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
componentDidMount() {
fetch(API)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
this.setState({
data:findresponse,
})
})
}
testfun(e) {
var target = e.target;
console.log(target)
}
render() {
return(
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron text-center">
{
this.state.data.map((dynamicData, key) =>
<div>
<a key={dynamicData.id} href={"/#/template"} onClick={this.testfun}>{dynamicData.name}</a>
</div>
)
}
</div>
</div>
</div>
</div>
)
}
}
export default Tournaments;
template.js:
import React, { Component } from "react";
import Tournaments from "./Tournaments";
const API = 'http://localhost:8080/api/tournaments';
class template extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
render() {
return(
<div>
<h1>clicked item</h1>
</div>
)
}
}
export default template;
And my API stores data looking like this:
[{"name":"abc","id":1,"organizer":"kla"},{"name":"fsdfs","id":2,"organizer":"fsdf"}]
I've tried to use onclick to get the value that was clicked but not sure how to display it in template.js.
Thanks for any help
I think you want to put user clicked item from Tournaments.js and display in Template.js
You can try to put Template inside Tournaments
Tournaments.js
import React, { Component } from "react";
import Template from './template';
class Tournaments extends Component {
constructor() {
super();
this.state = {
data: [],
clickedData: []
}
}
testfun(e) {
var target = e.target;
console.log(target);
let newClickedData = [];
newClickedData.push(target);
this.setState({
clickedData: newClickedData
});
}
render() {
return (
<div>
...
...
<Template clickedData={this.state.clickedData} />
</div>
);
}
}
export default Tournaments;
Template.js
import _ from 'lodash';
import React, { Component } from "react";
class template extends Component {
render() {
let clickedData = this.props.clickedData;
let displayClickedData = _.map(clickedData, (item) => {
return <div>item</div>;
});
return(
<div>
{displayClickedData}
</div>
)
}
}
export default template;
I would suggest picking one of the following options:
Wrap both Tournaments and Tournament in some parent component. Then if you click on any specific tournament, you can change its ID in state. If ID is null, you render list of tournaments, if ID is defined, you render your tournament component. That way you would lose the URL effect.
You can pass ID as GET parameter in URL and then read it in your Tournament component, so your code would look similar to this <a href={`/#/template?id=${dynamicData.id}`}>{dynamicData.name}</a>
You can try out React Router which would handle all that for you
I'm totally stuck with passing data from container to component When using Meteor and React. I thought I had just copied the code from Meteor React tutorial and customized a little bit, but it doesn't work somehow. What I wanna do is getting data from a database(QuestionModel) and simply output in a view. According to an error message in browser, this.props.questions in renderQuestions() is undefined... But I explicitly passed the data to the component.
Could anyone help me out? Thank you.
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import { Questions as QuestionsModel } from '../../api/questions.js';
import { QuestionList } from '../QuestionList.jsx';
class Questions extends Component{
renderQuestions(){
let filteredQuestions = this.props.questions;
//This doesn't work at all...
console.log(this.props.questions);
return filteredQuestions.map((question) => (
<QuestionList key={question._id} question={question} />
));
}
render(){
return (
<div className="questionlist">
<ul>{this.renderQuestions()}</ul>
</div>
);
}
}
Questions.propTypes = {
questions: PropTypes.array.isRequired,
};
export default QuestionsContainer = createContainer(() => {
//This console.log outputs the data correctly.
console.log(QuestionsModel.find({}).fetch());
const questions = QuestionsModel.find({}).fetch();
return {
questions,
};
}, Questions);
What is the code of your QuestionList component?
I just replaced it with <li key={question._id}>{question.question}</li> and it works perfectly for me.
Something else: do you import /imports/api/questions.js'; server-side?
Here is my code:
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import { Questions as QuestionsModel } from '../api/questions.js';
// import { QuestionList } from '../QuestionList.jsx';
class Questions extends Component{
renderQuestions(){
let filteredQuestions = this.props.questions;
//This doesn't work at all...
console.log(this.props.questions);
return filteredQuestions.map((question) => (
<li key={question._id}>{question.question}</li>
));
}
render(){
return (
<div className="questionlist">
<ul>{this.renderQuestions()}</ul>
</div>
);
}
}
Questions.propTypes = {
questions: PropTypes.array.isRequired,
};
export default QuestionsContainer = createContainer(() => {
//This console.log outputs the data correctly.
console.log(QuestionsModel.find().fetch());
const questions = QuestionsModel.find({}).fetch();
return {
questions,
};
}, Questions);
In the renderList(), I have a delete button that will delete the content once it is clicked. I am not sure where to put the setState so I put it inside on the onClick(). This doesn't work. I would like to know if I am doing this correct or if there is a better way to solve this.
onClick Function
onClick={() => {
this.props.deleteBook(list.book_id);
this.setState({delete: list.book_id});
}}>
React.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { selectUser } from '../actions/index.js';
import { deleteBook } from '../actions/index.js';
import _ from 'lodash';
class myPage extends Component {
constructor(props) {
super(props);
this.state = {
delete: 0
}
}
componentWillMount() {
this.props.selectUser(this.props.params.id);
}
renderList() {
return this.props.list.map((list) => {
return (
<li className='book-list'
key={list.book_id}>
{list.title}
<button
value={this.state.delete}
onChange={this.onClickChange}
onClick={() => {
this.props.deleteBook(list.book_id);
this.setState({delete: list.book_id});
}}>
Delete
</button>
</li>
);
})
}
render() {
const {user} = this.props;
const {list} = this.props;
if(user) {
return(
<div>
<h2>Date Joined: {user.user.joined}</h2>
<h1>My Page</h1>
<h2>Username: {user.user.username}</h2>
<div>My Books:
<h1>
{this.renderList()}
</h1>
</div>
</div>
)
}
}
}
function mapStateToProps(state) {
return {
user: state.user.post,
list: state.list.all
}
}
export default connect(mapStateToProps, { selectUser, deleteBook })(myPage);
Based on your use of mapStateToProps, seems like you are using Redux. Your list of books comes from the Redux store as props which is external to the component.
You do not need this.state.delete in the component. As state is managed by Redux, it seems like the bug is in your Redux code and not React code. Look into the reducers and ensure that you are handling the delete item action correctly.