React Sort By Like - reactjs

I am trying to figure out how to add an onClick feature that will then sort the likes in descending order. AKA each project has a 'like' button. I want to add another button to the page to allow the user to sort the project likes by descending order.
import React from 'react';
import ProjectsListItem from './ProjectsListItem'
const Project = ({ projects }) => {
const renderProjects = projects.projects.map(project =>
<ProjectsListItem project={project} key={project.id}/>
);
return (
<div className="container">
<div className="row">
{renderProjects}
</div>
</div>
);
};
export default Project;
Page 2
class ProjectsListItem extends Component {
handleOnClick = () => {
this.props.likeProject(this.props.project)
}
onClick = () => {
this.props.sortBy(this.props.project.like)
}
render() {
return(
<div>
<div className="col-sm-4">
<div className="container-fluid text-left">
<h4> <Link key={this.props.project.id} to=
{`/projects/${this.props.project.id}`}>{this.props.project.title}
</Link> </h4>
<h5> {this.props.project.studio}</h5>
<CounterButton project={this.props.project} likeProject=
{this.handleOnClick}/>
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
projects: state.projects
}
}
export default connect(mapStateToProps, {likeProject})
(ProjectsListItem);

You would have to make an event handler such as
https://reactjs.org/docs/handling-events.html
In this case you would probably want to do
onSortClick(e) {
e.preventDefault();
this.props.sorted = true
}
bind that to your click handler like this:
<CounterButton project={this.props.project} likeProject=
{this.onSortClick.bind(this)}/>
Hope this helps.

Related

React change css style of a div in another component by button clicking in another component

on my Project I have a banner on top of my site with 2 buttons. when I click the button profile I want it to change the css style of a div in another component.
this is my code for the banner:
import Profile from "./Profile";
function Banner() {
const invis=false;
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={Profile.changeStyle}>Profile</button>
</span>
</div>
);
}
export default Banner;
this is my code for the div in the other component:
import "../index.css";
import React, { useState } from "react";
const Profile = () => {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div>
<div className={style}> hellllo</div>
</div>
);
};
export default Profile;
I can only find information about this with parent-child components.
They said I should use a usestate import but I can't seem to get it working. what's the proper way to do this?
All you need is lift your state to parent component, if you have a long trip to your common ancestor you can try to use a context. Attached a working example. Hope it helps!
const Banner = ({ onClickHandler }) => {
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={() => onClickHandler()}>Profile</button>
</span>
</div>
)}
const Profile = ({ style }) => {
return (
<div>
<div className={style}>I'm your profile :)</div>
</div>
);
};
const App = () => {
// We lift the state
const [style, setStyle] = React.useState("profile-hidden");
const profileHandler = () => {
setStyle(style === 'profile-hidden'
? 'profile-displayed'
: 'profile-hidden')
}
return(
<div>
<Banner onClickHandler={profileHandler} />
<Profile style={style} />
</div>
)
}
// Render
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
.profile-hidden {
display: none;
}
.profile-displayed {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>
You cannot use this syntax for React Components COMPONENT.method
, in your case onClick={Profile.changeStyle} !
Instead you should make Banner parent component and use Profile component as child inside it or vise versa !
then You should pass the state style as props so then you will be able to use its value.
your code should look like this :
function Banner() {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={changeStyle}>Profile</button>
</span>
<Profile style={style} />
</div>
);
}
export default Banner;
and your Profile component :
const Profile = (props) => {
return (
<div>
<div className={props.style}> hellllo</div>
</div>
)
}

How to change a style of an HTML element in React?

I have two React components
class App extends React.Component {
render() {
return (
<div id="appWrapper">
<ConfigureWindow />
<button id="configureClocksButton">Configure clocks</button>
<section id="clocksHere"></section>
</div>
);
}
}
const ConfigureWindow = () => (
<div id="configureWindowWrapper">
<div id="configureWindow">
<section id="addCitySection">TODO: adding a city</section>
<div id="verticalLine"></div>
<section id="listOfCities">
<header>
<h1>Available cities</h1>
<div id="closeConfigureWindowWrapper">
<img src="..\src\images\exit.png" id="closeConfigureWindow" alt="" />
</div>
</header>
<section id="availableCities"></section>
</section>
</div>
</div>
);
I want "ConfigureWindow" to be shown when "configureClocksButton". I tried to execute it with props, state and a function but got errors. It also would be nice if you explain me how to create new React components with React functions?
You probably want to use the React.JS event onClick (https://reactjs.org/docs/handling-events.html), and a state to store the action. To create a function component, you just have to return the JSX you want to render, and use hooks (https://reactjs.org/docs/hooks-intro.html) and then do a conditional rendering (https://reactjs.org/docs/conditional-rendering.html):
const App = () => {
const [toggleConfiguration, setToggleConfiguration] = useState(false)
return (
<div id="appWrapper">
{toggleConfiguration && <ConfigureWindow />}
<button onClick{() => setToggleConfiguration(true)} id="configureClocksButton">Configure clocks</button>
<section id="clocksHere"></section>
</div>
);
}
It's a bit difficult to understand your post, but I gather you want to click the button with id="configureClocksButton" and conditionally render the ConfigureWindow component.
You can accomplish this with some boolean state, a click handler to toggle the state, and some conditional rendering.
class App extends React.Component {
this.state = {
showConfigureWindow: false,
}
toggleShowConfigureWindow = () => this.setState(prevState => ({
showConfigureWindow: !prevState.showConfigureWindow,
}))
render() {
return (
<div id="appWrapper">
{showConfigureWindow && <ConfigureWindow />}
<button
id="configureClocksButton"
onClick={this.toggleShowConfigureWindow}
>
Configure clocks
</button>
<section id="clocksHere"></section>
</div>
);
}
}
A function component equivalent:
const App = () => {
const [showConfigureWindow, setShowConfigureWindow] = React.useState(false);
const toggleShowConfigureWindow = () => setShowConfigureWindow(show => !show);
return (
<div id="appWrapper">
{showConfigureWindow && <ConfigureWindow />}
<button
id="configureClocksButton"
onClick={toggleShowConfigureWindow}
>
Configure clocks
</button>
<section id="clocksHere"></section>
</div>
);
}

adding and removing a classList in react js

I am using functional component in react js , in the below code
the class right-panel-active is not being added / is undefined. Someone help to enable the class be added when the button is toggled
import React from 'react';
import './style.css';
import {
Modal,
DropdownMenu
} from '../MaterialUI';
/**
* #author
* #function Header
**/
const Header = (props) => {
const container = () => {
document.getElementById('container');
}
const signUpButton = () => {
container.classList.add('right-panel-active');
};
const signInButton = () => {
container.classList.remove('right-panel-active');
};
return (
<div className="header">
<div className="container" id="container">
<button className="ghost" id="signIn" onClick={signInButton} >Sign In</button>
</div>
<div className="overlay-panel overlay-right">
<p>Enter your personal details and start journey with us</p>
<button className="ghost" id="signUp" onClick={signUpButton} >Sign Up</button>
</div>
</div>
)
}
export default Header
You are not utilising any of React's functionality.
Read about state management in React
and Event Handlers in React
const Header = (props) => {
const [isContainerActive, setIsContainerActive] = React.useState(false);
const signUpButton = () => {
setIsContainerActive(false);
};
const signInButton = () => {
setIsContainerActive(true);
};
return (
<div className="header">
<div id="container" className={`container${isContainerActive ? " right-panel-active" : ""}`}>
<button className="ghost" id="signIn" onClick={signInButton}>Sign In</button>
</div>
<div className="overlay-panel overlay-right">
<p>Enter your personal details and start journey with us</p>
<button className="ghost" id="signUp" onClick={signUpButton}>Sign Up</button>
</div>
</div>
);
}
ReactDOM.render(<Header />, document.getElementById("root"));
.header {height: 120px;}
.container {float:left;}
.overlay-right {display: none;background: red;float:right;height:100%;}
.right-panel-active ~ .overlay-right {display: inline-block;}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
PS: I also recommend https://www.npmjs.com/package/classnames , or the cx library for className management.
I think the best solution for this is to making a state and handle the style by a ternarian
function Welcome(props) {
const {name} = props;
return (
<h1 style={name === 'Sara' ? right-panel-active : right-panel-inactive}>Hello, {name}</h1>
)}
function App() {
return (
<div>
<Welcome name="Sara" />
</div>
);
}
This is the React way of doing,
You have to keep a local state (useState) and track the button click and based on the state change update the class to the container. You shouldn't directly change the DOM.
Click on the button to see the CSS is adding or not.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [isSignUp, setSignUp] = useState(true);
return (
<div id="container" className={isSignUp ? "right-panel-active" : ""}>
<button onClick={() => setSignUp(false)}>SignIn</button>
<button onClick={() => setSignUp(true)}>SignUp</button>
//for testing the change
{isSignUp ? "right-panel-active added" : "right-panel-active removed"}
</div>
);
}
Sample working code - https://codesandbox.io/s/fragrant-http-qo6du?file=/src/App.js
No need to add click event with vanilla js, you could add an React onClick event. You forgot to return the container.
// if you use curly braces you must return the value
const container = () => {
return document.getElementById('container');
};
// or skip the curly braces
const container = () =>
document.getElementById('container');

react redux two components

I have a component that will display the products which is coming from backend and a component that receives the products to filter but I have doubt that receive by redux my product list.
should i put for my filters component receive?
or should return the same as I get in my product component?
or should I create an action to filter what I need already?
my home:
return (
<div className="container">
<h1>Shopping</h1>
<hr />
<div className="row">
<div className="col-md-3"><Filters/></div>
<div className="col-md-9"><Products/></div>
</div>
</div>
)
my component products:
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { ProductsFetchData } from '../../store/actions/productsFetch';
import util from '../../util';
class HomeProducts extends Component {
componentDidMount() {
this.props.fetchData('/products');
}
render() {
const productItems = this.props.products.map( product => (
<div className="col-md-4 pt-4 pl-2">
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
)
return (
<div className="container">
<div className="row">
{productItems}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
products: state.Products,
hasErrored: state.ProductsHasErrored,
isLoading: state.ProductsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: () => dispatch(ProductsFetchData())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeProducts);
my components filter
import React, { Component } from 'react';
import './style.css'
class FilterHome extends Component {
render() {
return (
<>
<div className="row">
<button className="filterbt btn btn-danger btn-rounded">Filters</button>
<div className=" mt-4 d-flex flex-column">
<p className="textCategory">CATEGORY</p>
<div className="category d-flex flex-column">
<p>Stat Trak</p>
<p>Normal</p>
</div>
<p className="textCategory">EXTERIOR</p>
<div className="category d-flex flex-column">
<p>Factory New ()</p>
<p>Minimal Wear ()</p>
<p>Field Tested ()</p>
<p>Well Worn ()</p>
<p>Battle Scarred ()</p>
</div>
</div>
</div>
</>
)
}
}
export default FilterHome;
1.redux-state: this is the registering point for all your api responses(all the data from back-end is stored here as prestine and is available as props to any container when you mapStateToProps).
2.local-state: this lives only in your container and all it's child components.
3.filter:
a)from server:
you make a request to the server and get a response of filtered products. this
is more practical.
eg: you have /products?page=1 and you want to search it by some category, let's
say by a specific company. with the data you have at the moment(page 1), you
may have only let's say 1 or even no product relevant to that company, but in fact there are n-numbers of products of the same company available at the server. so this can only be assumed as the
most practical way.
b)filtering from the local-state:
if this is what your'e trying to achieve,
1. you need only one container, HomeProducts
2. make ProductItems as a component. wer'e gonna reuse this component to render both.
**you wrote your filter as an independent container. but those filter functionality should be availabe inside the home page itself. isn't it, i mean you're filtering from the home page itself not from another page. if so, add it to the home page itself
1.HomePage
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { ProductsFetchData } from '../../store/actions/productsFetch';
import util from '../../util';
import ProductItems from '<<..your relative path>>'
import FilterHome from '<<..your relative path>>'
class HomeProducts extends Component {
constructor(props) {
super(props)
this.state = {
productList: null,
}
}
componentDidMount() {
//this.props.fetchData('/products');
this.props.fetchData('page=1');
}
componentWillReceiveProps(nextProps) {
const { productList } = this.state
const { products } = this.props
// this only handles when local state is empty. add your logic here..
!productList && this.setState(prevState => ({
...prevState,
productList: products,
}))
}
handleFilter = (category) => {
// if it's an api call
const { fetchData } = this.props
fetchData(`page=1&category=${category}`)
//or you simply want to filter this local state(not-recommended)
const { products } = this.props
const productsList = [...products].filter(item => item.category === category)
this.setState(prevState => ({
...prevState,
productsList,
}))
}
render() {
const { productList } = this.state
const { handleFilter } = this
return (
<div className="container">
<FilterHome {...{ handleFilter }} />
<ProductItems {...{ productsList }} />
</div>
)
}
}
const mapStateToProps = (state) => {
return {
products: state.Products,
hasErrored: state.ProductsHasErrored,
isLoading: state.ProductsIsLoading
};
};
//it may not suit depends on your api, but you get the idea..
const mapDispatchToProps = (dispatch) => {
return {
// fetchData: () => dispatch(ProductsFetchData())
fetchData: params => dispatch(ProductsFetchData(`/products?${params}`))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeProducts);
2.ProductItems
import React from 'react'
const ProductItem = ({ product }) => {
return (
<div className="col-md-4 pt-4 pl-2">
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
}
const ProductItems = ({ productList }) => {
return (
<div className="row">
{productList && productList.map(product => <ProductItem key={product.id} {...{ product }} />)}
</div>
)
}
export default ProductItems
3.FilterHome
import React from 'react'
const FilterHome = ({ handleFilter }) => {
return (
<div className="row">
<button className="filterbt btn btn-danger btn-rounded">Filters</button>
<div className=" mt-4 d-flex flex-column">
<p className="textCategory">CATEGORY</p>
<div className="category d-flex flex-column">
<a href="" className="text-decoration-none" onClick={() => handleFilter('stat_trak')}><p>Stat Trak</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('normal')}><p>Normal</p></a>
</div>
<p className="textCategory">EXTERIOR</p>
<div className="category d-flex flex-column">
<a href="" className="text-decoration-none" onClick={() => handleFilter('factory_new')}><p>Factory New ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('minimal_wear')}><p>Minimal Wear ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('field_tested')}><p>Field Tested ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('well_worn')}><p>Well Worn ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('battle_scarred')}><p>Battle Scarred ()</p></a>
</div>
</div>
</div>
)
}
export default FilterHome
i roughly re-wrote it, may contain bugs..
first add it to the local state and employ a call back to the filter component..
handleFilter = (category) => {
const { Products } = this.state
const products = {...Products}
//or depends on the type, so it wont mutate the real data>> const products = [...Products]
return products.filter(item => item.category === category)
}
this is what is understood from your comment. is that it?

react-redux: Rendering a component after an API call

I am building an app which uses user input and shows number of recipes and they can click on recipe card to view ingredients as well. Every time they click on recipe card I make an API call to get appropriate recipe ingredient. But I am not able to figure out how to show the component which contains the recipe ingredients. I tried with conditional routing and conditional rendering as well but couldn't find the solution.
Recipe_Template.js
export class RecipeTemplate extends Component {
renderRecipe = recipeData => {
return recipeData.recipes.map(recipeName => {
return (
<div className="container">
<div className="row">
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<a
href={recipeName.source_url}
target="_blank"
onClick={() => {
this.props.fetchRecipeId(recipeName.recipe_id);
}}
>
<img
src={recipeName.image_url}
className="mx-auto d-block img-fluid img-thumbnail"
alt={recipeName.title}
/>
<span>
<h3>{recipeName.title}</h3>
</span>
</a>
<span}>
<h3>{recipeName.publisher}</h3>
</span>
</div>
</div>
</div>
);
});
};
render() {
return (
<React.Fragment>
{this.props.recipe.map(this.renderRecipe)}
</React.Fragment>
);
}
}
Recipe_Detail.js
class RecipeDetail extends Component {
renderRecipeDetail(recipeData) {
return recipeData.recipe.ingredients.map(recipeIngredient => {
return <li key={recipeIngredient}>recipeIngredient</li>;
});
}
render() {
if (this.props.recipeId === null) {
return <div>Loading...</div>;
}
return <ul>{this.props.recipeId.map(this.renderRecipeDetail)}</ul>;
}
}
function mapStateToProps({ recipeId }) {
return { recipeId };
}
export default connect(mapStateToProps)(RecipeDetail);
Not entirely sure why you would need Redux here (unless it's being shared among other nested components), but I'm fairly certain you can just utilize React state.
One approach would be to configure your routes as such:
<Route path="/recipes" component={Recipes} />
<Route path="/recipe/:id" component={ShowRecipe} />
When the user sends a query, gets some results, and you display all matching recipes to a Recipes component. Each recipe then has a name (and other associated displayable data) and a clickable link:
<Link to={`/recipe/id?recipeId=${recipeId}`}>View {recipeName} Recipe</Link>
which for simplicity sake might look like:
<ul>
<Link to="/recipe/id?recipeId=08861626">View Prosciutto Bruschetta Recipe</Link>
<Link to="/recipe/id?recipeId=04326743">View Pasta Bundt Loaf Recipe</Link>
...etc
</ul>
When the user clicks on the link, react-router sends the user to the ShowRecipe component with a unique recipeId.
ShowRecipe then makes another AJAX request to get the recipe details:
ShowRecipe.js
export default class ShowRecipe extends Component {
state = { recipeDetail: '' }
componentDidMount = () => {
const { recipeId } = this.props.location.query; // <== only natively available in react-router v3
fetch(`http://someAPI/recipe/id?recipeId=${recipeId}`)
.then(response => response.json())
.then(json => this.setState({ recipeDetail: json }));
}
render = () => (
!this.state.recipeDetails
? <div>Loading...</div>
: <ul>
{this.state.recipeDetail.map(ingredient => (
<li key={ingredient}>ingredient</li>
)}
</ul>
)
}
Another approach:
Have the recipeDetails stored and available within the original fetched recipes JSON. Then map over the recipes and create multiple <Card key={recipeId} recipeName={recipeName} recipeDetail={recipeDetail} /> components for each recipe.
which for simplicity sake might look like:
<div>
{this.state.recipes.map(({recipeId, recipeName, recipeDetail}), => (
<Card key={recipeId} recipeName={recipeName} recipeDetail={recipeDetail} />
)}
</div>
Then each individual Card has it's own state:
Card.js
export default class Card extends Component {
state = { showDetails: '' }
toggleShowDetails = () => this.setState(prevState => ({ showDetails: !this.state.showDetails }))
render = () => (
<div>
<h1>{this.props.recipeName} Recipe</h1>
<button onClick={toggleShowDetails}> {`${!this.state.showDetails ? "Show" : "Hide"} Recipe<button>
{ this.state.showDetails &&
<ul>
{this.props.recipeDetail.map(ingredient => (
<li key={ingredient}>ingredient</li>
)}
</ul>
}
)
}
Therefore, by default the recipeDetail is already there, but hidden. However, when a user clicks the Card's button, it will toggle the Card's showDetails state to true/false to display/hide the recipe detail.

Resources