Just started with the react and some simple things can get hard after years of jQuery
I want to render list of books and since the description is too long to display I want to limit the height of the div. onClick I want to display full description text and close it if clicked again.
like so: https://jsfiddle.net/nb1u1f9t/
Here is my function that renders books list:
renderBooks(){
return(
<div>
<h3>List of available books</h3>
<ul className="list-group">
{this.props.books.map((book)=>{
return (
<li key={book.id} className="list-group-item">
<div className="cover-img"><img src={book.cover_img} alt="" className="img-responsive" /></div>
<div className="book-info">
<ul className="list-group">
<li className="list-group-item active"><h4>Name: {book.name} </h4></li>
<li className="list-group-item">Pages: {book.pages_i}</li>
<li className="list-group-item">Genre: {book.genre_s}</li>
<li className="list-group-item">Price: {book.price}</li>
<li className="list-group-item">Description: <div className="description-frame">{renderHTML(book.description)}</div><div className="view-all" onClick={}>View All</div></li>
</ul>
</div>
</li>
);
})}
</ul>
</div>
);
I would appreciate the general idea how that can be accomplished in React style? I feel there should be something related to the state but cannot think of how to do that correctly. Plus not sure how the context for the specific book should be handled through the click event.
I would have two react components, BookList and Book.
Book would have a boolean value on its state to indicate whether it was expanded or not. It would also have an onClick handler which toggles the expanded state by calling this.setState({ expanded: !this.state.expanded })
Then it would just be up to book's render function to look at the state, and apply an additional CSS class for the case the book is not expanded, as per Kenneth's comment.
Adding a code in case somebody need the same solution
That is how my new code looks like:
component that renders books list:
import React, {Component} from 'react';
import BookDescription from './description_render';
export default class RenderBooks extends Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<h3>List of available books</h3>
<ul className="list-group">
{this.props.books.map((book)=>{
return (
<li key={book.id} className="list-group-item">
<div className="cover-img"><img src={book.cover_img} alt="" className="img-responsive" /></div>
<div className="book-info">
<ul className="list-group">
<li className="list-group-item active"><h4>Name: {book.name} </h4></li>
<li className="list-group-item">Pages: {book.pages_i}</li>
<li className="list-group-item">Genre: {book.genre_s}</li>
<li className="list-group-item">Price: {book.price}</li>
<li className="list-group-item"><BookDescription description={book.description}></BookDescription></li>
</ul>
</div>
</li>
);
})}
</ul>
</div>
);
}
}
New component that holds state for the clicked book description
import React, {Component} from 'react';
import renderHTML from 'react-render-html';
export default class BookDescription extends Component{
constructor(props){
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleViewClick = this.handleViewClick.bind(this);
}
handleViewClick(){
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render(){
return(
<div>
Description: <div className={this.state.isToggleOn ? 'description-frame closed' : 'description-frame'}>{renderHTML(this.props.description)}</div><div className="view-all" onClick={this.handleViewClick}>{this.state.isToggleOn ? 'View All' : 'Close'}</div>
</div>
)
}
}
Related
I am trying to add the Auth0 button to a navbar but the jsx linter does not like it when I add javascript. I need the conditional so it shows up for non registered users. I have tried importing it from another component ion React as well as adding it directly in the jsx with no luck. I keep getting isAuthenticated' is not defined and loginWithRedirect' is not defined. Not sure what to do next. Thanks.
import $ from 'jquery'
import '../styles/nav.scss'
import button from '../components/GoogleButton/Button.jsx'
import { auth0 } from './auth0/react-auth0-spa'
export default class NavBar extends Component {
componentDidMount() {
$(document).ready(function() {
$('.mobile-button a').click(function(e) {
$(this)
.parent()
.parent()
.toggleClass('open')
$(this).html($(this).html() === 'Close Menu' ? 'Menu' : 'Close Menu')
e.preventDefault()
})
})
}
render() {
return (
<div>
<header class='header'>
<div class='container'>
<h1 class='site-title'>Super Cool Web App!</h1>
<span class='site-tagline'>Because Andy made this!</span>
</div>
</header>
<nav class='main-nav'>
<div class='container'>
<ul>
<li class='mobile-button'>
<a href='/'>Menu</a>
</li>
<li>
<a href='/'>About</a>
</li>
<li>
{/* this is where the problem lies */}
{!isAuthenticated && (
<button onClick={() => loginWithRedirect({})}>Log in</button>
)}
</li>
<li>
<a href='/'>Methods</a>
</li>
<li>
<a href='/'>Results</a>
</li>
<li>
<a href='/'>Contact</a>
</li>
<li>
<a href='/'>Methods</a>
</li>
<li>
<a href='/'>Results</a>
</li>
<li>
<a href='/'>Contact</a>
</li>
</ul>
</div>
</nav>
</div>
)
}
}```
authO is for initializing you need to use useAuthO to access the api elsewhere in your project.
Change your import statement to:
import { useAuth0 } from "../react-auth0-spa";
Then deconstruct AuthO methods isAuthenticated and loginWithRedirect.
Right under render and before your return put:
const {isAuthenticated , loginWithRedirect} = useAuth0
https://auth0.com/docs/quickstart/spa/react#create-the-navbar-component
I have a problem with a navigation responsive menu.
When I resize the page, I can see the hamburger menu and everything works fine.But I am trying to put a toggle or slidetoggle in react like in jquery.I created a toggle button but does not work correctly. Above is the code, I created a handleClick button for the hamburger menu and a state cond. className="mynav" in css file is display:none;. I want when the size of page is small and when I push the hamburger button to see the menu.
import React, { Component } from 'react'
import './Navbar.css';
import {Link} from 'react-router-dom';
export default class Navbar extends Component {
state = {
cond: false,
}
handleClick=()=>{
this.setState({
cond:!this.state.cond
})
}
render() {
return (
<nav>
<div className="mylogo">
<div className="logo">
logo
</div>
<div id="mybtn" onClick={this.handleClick}>
<div className="bar1"></div>
<div className="bar2"></div>
<div className="bar3"></div>
</div>
</div>
{this.state.cond ? <div className="mynav" >
<ul>
<li>
<Link to='/'>home</Link>
</li>
<li>
<Link to='/about'>About</Link>
</li>
<li>
<Link to='/projects'>Projects</Link>
</li>
<li>
<Link to='/contact'>Contact</Link>
</li>
</ul>
</div> :false
}
</nav>
)
}
}
Wrap you state declaration in a constructor, something like this:
export default class Navbar extends Component {
constructor(props) {
super(props)
this.state = {
cond: false,
};
}
Then your onClick method will have access to the keyword 'this'. It wasn't able to access this.state without that.
I'm new with React.js. I'm making filter by name and address but I don't know how to do this with separate components. I have main component Speakers - in this component I receive json and send this data to Filter and List. In List.js I get data and display all speaker items(all json). In Filter I want to make search by name and address. I don't know how to bind component filter and list. I'll appreciate if you help me. I know that Redux help working with data in React but I want to understand how to do this without it.
enter image description here
Speakers.js
import React, {Component} from 'react';
import Filters from './Filters';
import List from './List';
class Speakers extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
items: []
}
}
componentDidMount() {
this.setState({isLoading: true});
fetch("https://randomapi.com/api/6de6abfedb24f889e0b5f675edc50deb?fmt=raw&sole")
.then(res => res.json())
.then(
(result) => {
this.setState({
items: result,
isLoading: false
});
console.log(result);
}
)
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
return (
<div className="speakers">
<div className="container-fluid">
<Filters getItems={this.state} />
<List getItems={this.state} />
</div>
</div>
);
}
}
export default Speakers;
List.js
import React, {Component} from 'react';
class List extends Component {
render() {
const {items, isLoading} = this.props.getItems;
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<div className="speakers__list">
<div className="row">
{items.map((item, index) => (
<div className="col-md-3" key={index}>
<div className="card form-group shadow">
<div className="card-body text-center">
<h5 className="card-title">{item.first} {item.last}</h5>
<p>{item.email}</p>
<p>{item.address}</p>
<p>{item.balance}</p>
<p>{item.created}</p>
</div>
</div>
</div>
))}
</div>
</div>
)
}
}
export default List;
Filters.js
import React, {Component} from 'react';
class Filters extends Component {
render() {
return (
<div className="filters">
<div className="alert shadow">
<form>
<div className="container-fluid">
<div className="row">
<div className="col-md-5">
<label>Name/Surname</label>
<input type="text" className="form-control" />
</div>
<div className="col-md-5">
<label>Address</label>
<input type="text" className="form-control"/>
</div>
<div className="col-md-2 align-self-center text-center">
<button className="btn btn-primary">Search</button>
</div>
</div>
</div>
</form>
</div>
</div>
);
}
}
export default Filters;
One way to move forward (possibly the best way, IMO) is this:
Come up with a data model to describe a single "filter". This could be as simple as an object that describes a name string and an address string that items need to be filtered using. The design of this is up to you; pick whatever works out best.
Then, build two sets of behavior into Speakers:
The ability to receive filtration instructions from Filters. You can achieve this by writing a function in Speakers that acts as a callback function when something changes in Filters. Pass this function as a prop to Filters and have Filters call it when its state changes (meaning, when you get user interaction).
The ability to send this filter object to List. Every time the callback function is called, have Speakers send it down to List. You can achieve this by storing what Filters sends back in Speakers' state and passing that state item down to List as a prop. That should update List's props every time Filters calls the callback function and thus affects Speakers' state.
Then, build behavior in List such that it changes its rendering behavior based on this filter object. Make sure to detect props updates so that it works on the fly.
How can I update my state value inside child component in this property {this.state.username} using of this function this.messageSubmit and how can I re-render the child render for displaying changed state values. Please help me anyone how can I update my state value inside and chat box because I'm new to reactjs
This is my child component chatting.js
import React from "react";
export class Chatting extends React.Component{
constructor(props){
super(props);
this.state={
username: 'shiva'
}
this.messageSubmit=this.messageSubmit.bind(this);
this.messageTextBox=this.messageTextBox.bind(this);
}
messageTextBox(event){
this.setState=({
username :event.target.value
})
}
messageSubmit(){
console.log(this.setState.username);
}
render(){
return(
<div>
<div className="chat-decription">
<div className="rt">
<div className="talk-bubble tri-right btm-right">
<div className="talktext">
<p>Flush to the bottom right. Uses .btm-right only.</p>
</div>
</div>
</div>
<div className="fl">
<div className="talk-bubble tri-right btm-right">
<div className="talktext">
<p>Flush to the bottom right. Uses .btm-right only.</p>
</div>
</div>
</div>
<div className="rt">
<div className="talk-bubble tri-right btm-right">
<div className="talktext">
<p> {this.setState.username}</p>
</div>
</div>
</div>
<div className="fl">
<div className="talk-bubble tri-right btm-right">
<div className="talktext">
<p>Flush to the bottom right. Uses .btm-right only.</p>
</div>
</div>
</div>
</div>
<div className="chat-textfiled">
<input type="text" className="form-control text-form" onChange={this.messageTextBox}/>
<input type="button" value="submit" onClick={this.messageSubmit}/>
</div>
</div>
)
}
}
This is my parent class
import React from "react";
import {render} from "react-dom";
import {Default} from "./component/Default";
import {Chatting} from "./component/Chatting";
import {BrowserRouter as Router,Route,Link,Switch } from 'react-router-dom';
// import Background from '../images/person_img.png';
class App extends React.Component{
constructor(){
super();
}
render(){
return(
<Router>
<div className="container">
<div className="container-top">
<div className="col-lg-4 leftmenu-contact-bg">
<div className="searchbox">
<div className="textbox-bg">
<input type="text" className="form-control" placeholder="Search"/>
</div>
</div>
<div className="ex1">
<a href="/chattting">
<div className="left-list">
<div className="left-img"><i className="material-icons icon-color">person</i></div>
<div className="right-content">dgfg</div>
</div>
</a>
</div>
</div>
<div className="col-lg-8 row">
<Switch>
<Route exact path='/' component={Default} />
<Route exact path='/chattting' component={Chatting} />
</Switch>
</div>
</div>
</div>
</Router>
);
}
}
render(<App/>,document.getElementById('app'));
setState is a function.
You should write:
this.setState({
username: event.target.value
});
Also, instead of
console.log(this.setState.username);
You should write
console.log(this.state.username);
And, again, instead of:
<p>{this.setState.username}</p>
You should write
<p>{this.state.username}</p>
In addition to the syntax corrections by #Rahamin, couple of pointers to your code -
Calling setState in the render function directly shouldn't be used, as it'll go into an infinite recursive function call stack. You'll probably be thrown an error of Maximum update depth exceeded.
Also, using console.logdirectly in the function that sets the state won't give you the desired output as they are queued and updated. It's best to include such console.log statements in the render itself.
Lastly, please post questions with good formatted code :)
So, I want to use collection class inside react I tried the following way
class Collect extends React.Component {
constructor(props) {
super(props);
this.state = {
}
};
render() {
return (
<div class="collection">
<a href="#!" class="collection-item">Name
<span class="badge"> 3 </span></a>
</div>
);
}
}
It did not work in the expected materializecss way. What would have gone wrong?
Or is this an issue with materializecss on react.
You need to use className instead of class. Like:
return (
<div className="collection">
<a href="#!" className="collection-item">Name
<span className="badge"> 3 </span></a>
</div>
);
}
Look HTML Attributes documentation.