How can I make this action in react work? - javascript

When I replace "this.props.fetchInfo(recipe.id)" with console.log(recipe.id), the "recipe.id" is logged when the div is clicked. However, the action is never fired. I have another console.log in my actual action creator that would log the id if it is actually passed in, but I just get an error (which I expect, but I figure I would at least get the id logged before the errors in my console). I'm not sure if the structure is set up correctly for the "Recipe" component although it appears as it is. Also, I'm not sure if there is a more correct way to do what I'm trying to do, which is to take in a piece (recipe.id) of the state from my last AJAX request and use it to make a second AJAX request to return the info I need. The following is the Recipe component:
import React, { Component } from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { fetchInfo } from "../actions";
// Here we take in the passed in props from the FoodList component and render
// the dishes for the inputted ingredients
class Recipe extends Component {
renderFood(food) {
return (
<div className="food-container">
{food.map(function(recipe) {
console.log(recipe.id);
return (
<div
className="indiv-recipe"
style={{
backgroundImage: "url(" + recipe.image + ")"
}}
onClick={() => this.props.fetchInfo(recipe.id)}
>
<div id="recipe-title"> {recipe.title}</div>
</div>
);
})}
</div>
);
}
render() {
return (
<div>
<h1>{this.props.foods.map(this.renderFood)}</h1>
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchInfo }, dispatch);
}
export default connect(
null,
mapDispatchToProps
)(Recipe);

Well, I coded something I believe you are trying to do.
class Recipe extends React.Component {
renderFood(foods) {
return (
<div>
{foods.map(recipe => (
<div
key={recipe.id}
onClick={() => this.props.fetchInfo(recipe.id)}
>
<div id="recipe-title">{recipe.title}</div>
</div>
)
)}
</div>
);
}
render() {
const { foods } = this.props;
return (
<div>
{this.renderFood(foods)}
</div>
);
}
}
const foodsList = [
{ title: "beans", id: 1 },
{ title: "rice", id: 2 },
];
class Main extends React.Component {
state = { received: false, info: null };
fetchInfo(id) {
this.setState({
received: true,
info: id,
});
}
render() {
const { received, info } = this.state;
return (
<div>
{received && (<div>{info}</div>)}
<Recipe
foods={foodsList}
fetchInfo={(id) => this.fetchInfo(id)}
/>
</div>
);
};
}
ReactDOM.render(<Main />, document.querySelector("#app"));
<div id="app"></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>
You are binding in the wrong way.
Replace
{food.map(function(recipe) {
with
{food.map(recipe => {

Related

Refactor class to function components in React

I'm having a hard time converting these 3 class components to function components, the class components are working i just am trying to convert them for learning purposes.
the API call: yelp.js
const { default: SearchBar } = require("../components/SearchBar/SearchBar");
const Yelp = {
searchYelp(term, location) {
return fetch(`/api/hello?term=${term}&location=${location}`)
.then((response) => {
// console.log(response)
return response.json()
}).then((jsonResponse) => {
// console.log(jsonResponse)
if (jsonResponse.businesses) {
return jsonResponse.businesses.map((business) => {
return {
id: business.id,
imageSrc: business.image_url,
name: business.name,
address: business.location.address1,
city: business.location.city,
state: business.location.state,
zipCode: business.location.zip_code,
category: business.categories.title,
rating: business.rating,
reviewCount: business.review_count,
}
})
}
})
}
}
export default Yelp
The Home component as a function that renders a SearchBar and BusinessList component: Home.js
import React, { useState } from "react";
import BusinessList from '../../../src/components/BusinessList/BusinessList';
import SearchBar from '../../../src/components/SearchBar/SearchBar';
import Yelp from '../../util/yelp';
const Home = (term, location) => {
const [businesses, setBusinesses] = useState([]);
const searchYelp = Yelp.searchYelp(term, location).then(businesses => {
setBusinesses(businesses)
})
return (
<>
<SearchBar searchYelp={searchYelp} />
<BusinessList business={businesses} />
</>
)
}
export default Home;
The Home component as a class: Home.js
// import React from 'react';
// import BusinessList from '../../../src/components/BusinessList/BusinessList';
// import SearchBar from '../../../src/components/SearchBar/SearchBar';
// import Yelp from '../../util/yelp';
// class Home extends React.Component {
// constructor() {
// super();
// this.state = {
// businesses: [],
// };
// this.searchYelp = this.searchYelp.bind(this);
// }
// searchYelp(term, location, sortBy) {
// Yelp.searchYelp(term, location, sortBy).then((businesses) => {
// this.setState({ businesses: businesses })
// })
// }
// render() {
// return (
// <>
// <SearchBar searchYelp={this.searchYelp} />
// <BusinessList businesses={this.state.businesses} />
// </>
// )
// }
// }
// export default Home;
The BusinessList component as a function that renders a Business component: BusinessList.js
import React, { useState } from "react";
import './BusinessList.css';
import Business from '../Business/Business';
function BusinessList(businesses) {
console.log(businesses)
return (
<div className="BusinessList">
{
businesses.map(business => {
<Business key={business.id} business={business} />
})
}
</div>
)
};
export default BusinessList;
The BusinessList component as a class: BusinessList.js
// import React from 'react';
// import './BusinessList.css';
// import Business from '../Business/Business';
// class BusinessList extends React.Component {
// constructor(props) {
// super(props)
// console.log(props.businesses)
// }
// render() {
// return (
// <div className="BusinessList">
// {
// this.props.businesses.map((business) => {
// return <Business key={business.id} business={business} />
// })
// }
// </div>
// )
// }
// };
// export default BusinessList;
The Business component as a function: Business.js
import React from "react";
import './Business.css';
const Business = (business) => {
return (
<div className="Business">
<div className="image-container">
<img src={business.business.imageSrc} alt={business.imageSrc} />
</div>
<h2>{business.business.name}</h2>
<div className="Business-information">
<div className="Business-address">
<p>{business.business.address}</p>
<p>{business.business.city} {business.state} {business.zipCode}</p>
</div>
<div className="Business-reviews">
<h3>{business.business.category}</h3>
<h3 className="rating">{business.business.rating}</h3>
<p>{business.business.reviewCount} reviews</p>
</div>
</div>
</div>
)
};
export default Business;
The Business component as a class: Business.js
// import React from "react";
// import './Business.css';
// class Business extends React.Component {
// render() {
// const { business } = this.props
// return (
// <div className="Business">
// <div className="image-container">
// <img src={business.imageSrc} alt={business.imageSrc} />
// </div>
// <h2>{business.name}</h2>
// <div className="Business-information">
// <div className="Business-address">
// <p>{business.address}</p>
// <p>{business.city} {business.state} {business.zipCode}</p>
// </div>
// <div className="Business-reviews">
// <h3>{business.category}</h3>
// <h3 className="rating">{business.rating}</h3>
// <p>{business.reviewCount} reviews</p>
// </div>
// </div>
// </div>
// )
// }
// };
// export default Business;
EDIT **
My attempt at SearchBar component as function: SearchBar.js
import React, { useState, useEffect } from "react";
import './SearchBar.css';
const SearchBar = (props) => {
const [term, setTerm] = useState('')
const [location, setLocation] = useState('')
const [sortBy, setSortBy] = useState('best_match')
const sortByOptions = {
'Best Match': 'best_match',
'Highest Rated': 'rating',
'Most Reviewed': 'review_count'
};
const handleSortByChange = () => {
setSortBy(sortBy)
// console.log(sortByOption)
console.log(sortBy)
}
const renderSortByOptions = (sortByOptions) => {
// console.log(Object.keys(sortByOptions))
return Object.keys(sortByOptions).map(sortByOption => {
let sortByOptionValue = sortByOptions[sortByOption]
// console.log(sortByOptionValue)
return <li
className={sortBy === sortByOption ? 'active' : ''}
onClick={handleSortByChange}
key={sortByOptionValue}>
{sortByOption}
</li>;
})
}
const handleTermChange = (event) => {
setTerm(event.target.value)
}
const handleLocationChange = (event) => {
setLocation(event.target.value)
}
const handleSearch = (event) => {
event.preventDefault()
props.searchYelp(term, location)
}
return (
<div className="SearchBar">
{props.searchYelp}
<div className="SearchBar-sort-options">
<ul>
{renderSortByOptions(sortByOptions)}
</ul>
</div>
<div className="SearchBar-fields">
<input
onChange={handleTermChange}
placeholder="Search Businesses"
/>
<input
onChange={handleLocationChange}
placeholder="Where?"
/>
<button className="SearchBar-submit" onClick={handleSearch}>Let's Go</button>
</div>
</div>
)
}
export default SearchBar;
EDIT**
SearchBar component as a class: SearchBar.js
import React from 'react';
import './SearchBar.css';
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: '',
location: '',
sortBy: 'best_match'
}
this.handleTermChange = this.handleTermChange.bind(this)
this.handleLocationChange = this.handleLocationChange.bind(this)
this.handleSearch = this.handleSearch.bind(this)
this.sortByOptions = {
'Best Match': 'best_match',
'Highest Rated': 'rating',
'Most Reviewed': 'review_count'
};
}
getSortByClass(sortByOption) {
// console.log(sortByOption)
if (this.state.sortBy === sortByOption) {
return 'active'
}
return ''
}
handleSortByChange(sortByOption) {
this.setState({
sortBy: sortByOption
})
}
handleTermChange(event) {
this.setState({
term: event.target.value
})
}
handleLocationChange(event) {
this.setState({
location: event.target.value
})
}
handleSearch(event) {
this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy)
event.preventDefault()
}
renderSortByOptions() {
return Object.keys(this.sortByOptions).map(sortByOption => {
let sortByOptionValue = this.sortByOptions[sortByOption]
console.log(sortByOptionValue)
return <li
onClick={this.handleSortByChange.bind(this, sortByOptionValue)}
className={this.getSortByClass(sortByOptionValue)}
key={sortByOptionValue}>
{sortByOption}
</li>;
})
}
render() {
return (
<div className="SearchBar">
{this.searchYelp}
<div className="SearchBar-sort-options">
<ul>
{this.renderSortByOptions()}
</ul>
</div>
<div className="SearchBar-fields">
<input onChange={this.handleTermChange} placeholder="Search Businesses" />
<input onChange={this.handleLocationChange} placeholder="Where?" />
<button className="SearchBar-submit" onClick={this.handleSearch}>Let's Go</button>
</div>
</div>
)
}
};
export default SearchBar;
I keep getting the error "Cannot read properties of undefined (reading 'map')
Or the error "Businesses.map is not a function"
Im also a little confused as to why when everything is converted to function components in my final Business component in order to get things to showup im required to pass things in as business.business.imageSrc instead of just business.imageSrc
First in Home searchYelp should be declared as a function so it can be passed as a callback to the SearchBar component.
const Home = () => {
const [businesses, setBusinesses] = useState([]);
const searchYelp = (term, location) => {
Yelp.searchYelp(term, location)
.then(businesses => {
setBusinesses(businesses);
});
};
return (
<>
<SearchBar searchYelp={searchYelp} />
<BusinessList business={businesses} />
</>
)
};
Then in BusinessList you need to access the passed business prop. Your current code is naming the props object businesses and then attempts to map it. It could be businesses.business.map, but by convention we name the props object props or simply destructure the props you want to use. You need to also return the Business component you are mapping to.
function BusinessList({ business }) {
return (
<div className="BusinessList">
{business.map(business => {
return <Business key={business.id} business={business} />;
})}
</div>
)
};
Same issue with the props object name in the Business component.
const Business = (props) => {
return (
<div className="Business">
<div className="image-container">
<img src={props.business.imageSrc} alt={props.business.imageSrc} />
</div>
<h2>{props.business.name}</h2>
<div className="Business-information">
<div className="Business-address">
<p>{props.business.address}</p>
<p>{props.business.city} {props.business.state} {business.zipCode}</p>
</div>
<div className="Business-reviews">
<h3>{props.business.category}</h3>
<h3 className="rating">{props.business.rating}</h3>
<p>{props.business.reviewCount} reviews</p>
</div>
</div>
</div>
)
};
BusinessList receives props, an object containing the props passed in.
The function parameter would either need to destructure it:
function BusinessList({ businesses }) { ... }
Or reference it off the props object:
function BusinessList(props) {
console.log(props.businesses)
// ...
}
Few notes:
Right now Yelp.searchYelp returns Promise<any[] | undefined>, i.e undefined is a legitimate value that the consume may get. Up to you to decide if setBusinesses(businesses) when businesses is undefined is useful or not, but in that case, handle it. Otherwise default to an empty array, setBusinesses(businesses ?? []) or throw an error.
Do not run side effects in the render phase, i.e call the api inside a useEffect:
React.useEffect(() => {
const searchYelp = Yelp.searchYelp(term, location).then(businesses => {
setBusinesses(businesses ?? [])
})
}, [term, location])
Lastly, const Business = (business) => { here business is actually the props object. You can simply destructure it const Business = ({ business }) => { to get the value directly.

Struggling to pass an index of an array as props to another component

I am trying to build an app in which a user can add a card to an array of cards, then switch the positions of a specific card with the card to the left or right. I wrote a function that I believe will switch a card with that on the left, but I am struggling to debug it because it seems that the index of the chosen card is not properly being passed down to the child component.
Here is my code so far:
CardList.js is what is attempting to pass the moveLeft method to cardItem
import React from "react";
import CardItem from "./CardItem";
import CardForm from "./CardForm";
import './Card.css';
class CardList extends React.Component {
state = {
cards: JSON.parse(localStorage.getItem(`cards`)) || []
// when the component mounts, read from localStorage and set/initialize the state
};
componentDidUpdate(prevProps, prevState) { // persist state changes to longer term storage when it's updated
localStorage.setItem(
`cards`,
JSON.stringify(this.state.cards)
);
}
render() {
const cards = this.getCards();
const cardNodes = (
<div style={{ display: 'flex' }}>{cards}</div>
);
return (
<div>
<CardForm addCard={this.addCard.bind(this)} />
<div className="container">
<div className="card-collection">
{cardNodes}
</div>
</div>
</div>
);
}
addCard(name) {
const card = {
name
};
this.setState({
cards: this.state.cards.concat([card])
}); // new array references help React stay fast, so concat works better than push here.
}
removeCard(index) {
this.state.cards.splice(index, 1)
this.setState({
cards: this.state.cards.filter(i => i !== index)
})
}
moveLeft(index, card) {
this.setState((prevState, prevProps) => {
return {cards: prevState.cards.map(( c, i)=> {
// also handle case when index == 0
if (i === index) {
return prevState.cards[index - 1];
} else if (i === index - 1) {
return prevState.cards[index];
}
})};
});
}
//moveRight(index, card) {
// ?
// }
getCards() {
return this.state.cards.map((card) => {
return (
<CardItem
card={card}
index={card.index}
name={card.name}
removeCard={this.removeCard.bind(this)}
moveLeft={this.moveLeft.bind(this)}
// moveRight={this.moveRight}
/>
);
});
}
}
export default CardList;
cardItem is struggling to find the index of the necessary card even though I passed that in as props. I am getting an error saying "×
TypeError: Cannot read property 'index' of undefined" originating from my CardList component.
import React from 'react';
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
class CardItem extends React.Component {
render() {
return (
<div>
<Card style={{ width: '15rem'}}>
<Card.Header as="h5">{this.props.name}</Card.Header>
<Card.Body>
<Button variant="primary" onClick={this.handleClick.bind(this)}>Remove</Button>
</Card.Body>
<Card.Footer style={{ display: 'flex' }}>
<i class="arrow left icon" onClick={this.leftClick.bind(this)} style={{ color: 'blue'}}></i>
{/*<i class="arrow right icon" onClick={rightClick(index, card)} style={{ color: 'blue'}}></i>*/}
</Card.Footer>
</Card>
</div>
)
}
handleClick(index) {
this.props.removeCard(index)
}
leftClick(index, card) {
this.props.moveLeft(index,card)
}
rightClick(index, card) {
this.props.moveRight(index, card)
}
}
export default CardItem;
How can I best pass down the necessary index as props? Thank you
Edit #1
I made an error in my addCard method, I never assigned the index to the card. I have fixed this and added a key property in my map return function but am now getting an error saying "×
TypeError: Cannot read property 'name' of undefined"
Please see the updated CardList.js below:
import React from "react";
import CardItem from "./CardItem";
import CardForm from "./CardForm";
import './Card.css';
class CardList extends React.Component {
state = {
cards: JSON.parse(localStorage.getItem(`cards`)) || []
// when the component mounts, read from localStorage and set/initialize the state
};
componentDidUpdate(prevProps, prevState) { // persist state changes to longer term storage when it's updated
localStorage.setItem(
`cards`,
JSON.stringify(this.state.cards)
);
}
render() {
const cards = this.getCards();
const cardNodes = (
<div style={{ display: 'flex' }}>{cards}</div>
);
return (
<div>
<CardForm addCard={this.addCard.bind(this)} />
<div className="container">
<div className="card-collection">
{cardNodes}
</div>
</div>
</div>
);
}
addCard(name, index) {
const card = {
name,
index
};
this.setState({
cards: this.state.cards.concat([card])
}); // new array references help React stay fast, so concat works better than push here.
}
removeCard(index) {
this.state.cards.splice(index, 1)
this.setState({
cards: this.state.cards.filter(i => i !== index)
})
}
moveLeft(index, card) {
this.setState((prevState, prevProps) => {
return {cards: prevState.cards.map(( c, i)=> {
// also handle case when index == 0
if (i === index) {
return prevState.cards[index - 1];
} else if (i === index - 1) {
return prevState.cards[index];
}
})};
});
}
//moveRight(index, card) {
// ?
// }
getCards() {
return this.state.cards.map((card) => {
return (
<CardItem
card={card}
key={card.index}
name={card.name}
removeCard={this.removeCard.bind(this)}
moveLeft={this.moveLeft.bind(this)}
// moveRight={this.moveRight}
/>
);
});
}
}
export default CardList;
There is a problem with your addCard & removeCard functions. State updates may be asynchronous in React, due to which you should not use this.state inside this.setState.
Eg: addCard should be as follows:
addCard(name, index) {
let card = {name,index};
this.setState((prevState, prevProps)=> {
return prevState.cards.concat(card);
})
}
removeCard should be modified likewise. The splice should be removed too, as the filter does the removing.
removeCard(index) {
this.setState(function(prevState,prevProps) {
return {cards: prevState.cards.filter(function(card,i) {
return i != index;
})};
});
}

React component that's rendered dynamically does not rerender on parent state changes

I have a component that I want to run through a non react animation library before render. This has prevented me from going the standard route of just using the standard hide/show logic. I initially tried to use ReactDOM.createPortal but that didn't render the component at all. Using ReactDOM.render, I've gotten the element to render correctly upon completion of the animation and I'm able to successfully propagate changes up to the "parent" state but the state change doesn't propagate back down to the "child". Here's my code:
Html
<div id="root"></div>
<div id="childPlaceholder"></div>
Javascript
import './App.css';
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
function App() {
const [data, updateData] = useState(0)
function add(val) {
console.log("add");
updateData(val);
}
function renderSubpage() {
let $el = document.getElementById("childPlaceholder");
// NonReactAnimationLibrary.ShowContainer($el);
ReactDOM.render(<Child number={data} add={add} />, $el);
// ReactDOM.createPortal(<Child number={data} add={add} />, $el);
}
return ( <>
<button onClick={renderSubpage}>
add child
</button>
<div> data: {data}</div>
</>
);
}
function Child(props) {
return <>
<button onClick={()=>{props.add(props.number + 1)}}>add number</button>
<div>child {props.number}</div>
</>
}
export default App;
Is it possible to do this in react?
Update 1:
So I've updated the code per Olivers response, it renders correctly using the portal but the child components still don't rerender on state changes in the Parent Component
const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");
function Child(args) {
return ReactDOM.createPortal(<>
<div>child: {args.number}</div>
<button onClick={()=>{args.add(args.number+1)}}>Increment base number</button>
</>, childRoot);
}
export default class App extends React.Component {
constructor() {
super();
this.state = { data: 0, number:0 };
}
add = (val)=> {
this.setState({
...this.state,
number: val
});
}
addChild = () => {
this.setState(prevState => ({data: prevState.data + 1}));
}
render() {
const children = Array(this.state.data)
.fill()
.map((_, i) => <Child key={i} number={0} add={this.add}/>);
return (
<div>
<button onClick={this.addChild}>
add child
</button>
<div> data: {this.state.data}</div>
{children}
</div>
);
}
}
ReactDOM.render(<App/>, root);
Update 2:
The culprit was found. Changed
number={0}
to
number={this.state.number}
and it works
React.createPortal must be used inside the render method (I used a class component because I cannot use hooks in the SO example, you can of course use a functional component).
You can use it in the App component like below or in the Child component :
const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");
function Child({number}) {
return <div>child {number}</div>;
}
class App extends React.Component {
constructor() {
super();
this.state = { data: 0 };
}
addChild = () => {
this.setState(prevState => ({data: prevState.data + 1}));
}
render() {
const children = Array(this.state.data)
.fill()
.map((_, i) => <Child key={i} number={i} />);
return (
<div>
<button onClick={this.addChild}>add child</button>
<div> data: {this.state.data}</div>
{ReactDOM.createPortal(children, childRoot)}
</div>
);
}
}
ReactDOM.render(<App/>, 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"></div>
<div id="childPlaceholder"></div>

i am not able to understand how props works in reactjs

I have written a component counter in a module named counter.jsx and now I am trying to import that component(counter) in a new module counter .jsx and using it four times in counters.jsx. now when I tried to print props in counters.jsx render method it is getting printed twice for every component . so it is printing props object 8 times on console for four components.why is it printing 8 times, can anyone explain me please
counter.jsx
import React, { Component } from 'react';
class Counter extends Component {
state = {count:0,
tags : ['tag1','tag2','tag3'],
tagObj : {'tag1':1 , 'tag2':2},
id:5
};
//User-def Functions
h=5;
formatCount()
{
if(this.state.count === 0)
{
return 'Zero';
}
else
{
return this.state.count;
}
}
// how to use map functions
renderList()
{
const List = this.state.tags.map( (tag) => <li key={tag} > <a href='/'>{tag}</a> </li> );
return (List.length===0)?<p>shopping cart is empty</p>: List ;
}
getBadgeClassess()
{
var classes = 'badge m-2 badge-';
classes += (this.state.count === 0) ? "warning" : "primary";
return classes;
}
handleCountIncrement = () => {
// console.log(incr);
this.setState( { count: this.state.count + 1 });
}
// Render Function
render() {
console.log("props" , this.props);
return(
// <React.Fragment>
<div>
<span className={this.getBadgeClassess()}>{this.formatCount()}</span>
<button onClick={ this.handleCountIncrement } className='btn btn-primary btn-sm' >Increment</button>
{/* <ul> */}
{/* { this.state.tags.map( tag => <li>{ tag }</li>) } */}
{/* {this.renderList()} */}
{/* </ul> */}
</div>
// </React.Fragment>
);
}
}
export default Counter;
counters.jsx
import React, { Component } from 'react';
import Counter from './counter';
class Counters extends Component {
state = {
counters : [
{ id:1 , value:0 },
{ id:2 , value:0 },
{ id:3 , value:0 },
{ id:4 , value:0 }
]
}
// renderCounters = () =>{
// }
render() {
console.log("props" , this.props);
return (
<div>
{this.state.counters.map( (counter) => ( <Counter key={counter.id} selected={true} />) ) }
</div>
);
}
}
export default Counters;
on console
enter image description here
React is going to call render several times even if you render the component once, you can't control that. If you want to have certain control then you need to use the lifecycle methods:
https://www.w3schools.com/react/react_lifecycle.asp

There is an error on the return ( and I cannot understand why

import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
class MyStories extends React.Component {
addFavorite = (e) => {
this.setState({
bgcolor: "blue"
})
}
render () {
const { stories } = this.props;
const { storyBriefs } = this.props.stories.length > 0 ?
stories.map(t => (<div className="menu-inner-container"><p key={t.id}><Link to={`/stories/${t.id}`}>{t.attributes.title}</Link>
<div className="addFavoriteCss"
style={{backgroundColor: this.state.bgColor}}
onClick={this.addFavorite}> Favorite</div>
</p></div>))
//refactor - create a button that will allow for us to mark which our favorites are
return (
{ this.props.storyBriefs }
);
}
}
const mapStateToProps = state => {
return {
stories: state.myStories
}
}
export default connect(mapStateToProps)(MyStories)
getting this error
./src/components/MyStories.js
Line 26: Parsing error: Unexpected token, expected ":"
return (
^
{ this.props.storyBriefs }
);
}
I converted a functional component to a class component so that I could manipulate the state in order to change the color of the favorite button -- (I cannot use hooks or redux for the button function) Can anyone tell me what I am doing wrong?
You need to complete the ternary operator by adding :
const storyBriefs = this.props.stories.length > 0 ?
stories.map(t => (<div className="menu-inner-container"><p key={t.id}><Link to={`/stories/${t.id}`}>{t.attributes.title}</Link>
<div className="addFavoriteCss"
style={{backgroundColor: this.state.bgColor}}
onClick={this.addFavorite}> Favorite</div>
</p></div>))
: [] // you need something here after the ':', an empty array could be useful in this case
return storyBriefs
or you could shorten it to
return stories.map(t => (<div className="menu-inner-container"><p key={t.id}><Link to={`/stories/${t.id}`}>{t.attributes.title}</Link>
<div className="addFavoriteCss"
style={{backgroundColor: this.state.bgColor}}
onClick={this.addFavorite}> Favorite</div>
</p></div>))
As Jaromanda X said { this.props.storyBriefs } isn't valid. you need to provide the key value pair unless the variable doesn't have dot notation then you can define the object like that
This was the final code and it works,
import React from "react"
import { connect } from "react-redux"
import { Link } from "react-router-dom"
class MyStories extends React.Component {
constructor(props) {
super(props);
this.state = {
button: false
};
this.addFavorite = this.addFavorite.bind(this);
}
addFavorite = id => {
this.setState({
button: id
});
};
render() {
return this.props.stories.map(t => (
<div className="menu-inner-container">
<p key={t.id}>
<Link to={`/stories/${t.id}`}>{t.attributes.title}</Link>
<button
key={t.id}
className={this.state.button===t.id ? "buttonTrue" : "buttonFalse"}
onClick={() => this.addFavorite(t.id)}
>
Favorites
</button>
</p>
</div>
));
}
}
//refactor - create a button that will allow for us to mark which our favorites are
const mapStateToProps = state => {
return {
stories: state.myStories
};
};
export default connect(mapStateToProps)(MyStories);

Categories

Resources