React render when using onClick - javascript

Wanted to know if there is way you can render the component without constructor.
Below is the my onClick code. My goal is to render when you click the button so that the button disappears.
I wasn't sure if there was way to render this without creating
constructor(props) {
super(props);
this.state = {}
}
<div>
<h1>Title: {post.title}</h1>
<h2>Pages: {post.pages}</h2>
<div>Reviews:</div>
<button
onClick={() => { this.props.addToMyPage(
{
userId: user.user.user_id,
bookId: post.book_id
}
)}}>
Add this to my page
</button>
</div>
)
d
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { selectBook } from '../actions/index';
import { addToMyPage } from '../actions/index';
import { Link } from 'react-router';
import { selectUser } from '../actions/index.js';
import { getBooks } from '../actions/index';
import _ from 'lodash';
class BookDetails extends Component {
constructor(props) {
super(props);
this.state = {
show: true
};
}
componentWillMount() {
this.props.selectBook(this.props.params.id)
if(this.props.user) {
this.props.selectUser(this.props.user.user.user_id);
}
else {
this.props.selectBook(this.props.params.id);
}
}
renderList() {
const elems = [];
const urlId = parseInt(this.props.params.id);
this.props.list.forEach((list) => {
console.log("list", list.book_id);
console.log("params", this.props.params.id)
if(list.book_id === urlId) {
console.log("true");
elems.push({
book: list.book_id
})
}
})
return elems;
}
render() {
const {post} = this.props;
const {user} = this.props;
const {list} = this.props;
const renderList = this.renderList();
const urlId = parseInt(this.props.params.id);
if(!post) {
return <div>Loading...</div>
}
if(user && list) {
if(urlId === _.get(renderList, '[0].book')) {
return (
<div>
<h1>Title: {post.title}</h1>
<h2>Pages: {post.pages}</h2>
<div>Reviews:</div>
</div>
)
}
else {
return (
<div>
<h1>Title: {post.title}</h1>
<h2>Pages: {post.pages}</h2>
<div>Reviews:</div>
{this.state.show && <button
onClick={() => { this.setState({show:false}, this.props.addToMyPage(
{
userId: user.user.user_id,
bookId: post.book_id
}
))}}>
Add this to my page
</button>
</div>
)
}
}
else {
return (
<div>
<h1>Title: {post.title}</h1>
<h2>Pages: {post.pages}</h2>
<div>Reviews:</div>
</div>
)
}
}
}
function mapStateToProps(state) {
return {
post: state.books.post,
user: state.user.post,
list: state.list.all
}
}
export default connect(mapStateToProps, {selectBook, addToMyPage, getBooks, selectUser})(BookDetails);

You can easily show the button based on the state of your function:
this.state = {
show: true
};
====
<div>
....
{this.state.show && <button
onClick={() => { this.props.addToMyPage(
{
userId: user.user.user_id,
bookId: post.book_id
}
); this.setState({show:false})}}>
Add this to my page
</button>
}
...
</div>
Once the button clicked - you change the state to show: false and this will cause the button to be removed from your DOM.

Related

Different class component and func component in handle event react

Can anyone help me explain it, because when use functional it work, but not when use class component
Different class component and func component in handle event react.
fyi it take input text search on child and at parent doing handle event and other
child use functional
import React from "react";
const Header = ({searchTitle,onSearch}) => {
return (
<div>
<header>
<h1>Notes</h1>
<div className="search">
<input
type="text"
placeholder="Search..."
value={searchTitle}
onChange={onSearch}
></input>
</div>
</header>
</div>
);
};
export default Header;
child use class component
import React, { Component } from "react";
export class HeaderPage extends Component {
render() {
const searchTitle = this.props.searchTitle;
const onSearch = this.props.onSearchHandler;
return (
<header>
<h1>Notes</h1>
<div className="search">
<input
type="text"
placeholder="Search..."
value={searchTitle}
onChange={onSearch}
></input>
</div>
</header>
);
}
}
export default HeaderPage;
parent class componet
import React, { Component } from "react";
import HeaderPage from "../organisms/HeaderPage";
import MainPage from "../organisms/MainPage";
import FooterPage from "../organisms/FooterPage";
import { getInitialData } from "../../utils/data";
import Header from "../organisms/Header";
export class PageNote extends Component {
constructor(props) {
super(props);
this.state = {
dataNotes: getInitialData(),
dataNotesFiltered: [],
searchTitle: "",
};
//binding
this.onAddNoteHandler = this.onAddNoteHandler.bind(this);
this.onDeleteHandler = this.onDeleteHandler.bind(this);
this.onArchivedHandler = this.onArchivedHandler.bind(this);
this.onSearchHandler = this.onSearchHandler.bind(this);
}
onAddNoteHandler({ title, body }) {
this.setState((prevState) => {
return {
dataNotes: [
...prevState.dataNotes,
{
id: +new Date(),
title,
body,
archived: false,
createdAt: new Date().toLocaleDateString(),
},
],
};
});
}
onDeleteHandler(id) {
const dataNotes = this.state.dataNotes.filter(
(dataNote) => dataNote.id !== id
);
this.setState({ dataNotes });
}
onArchivedHandler(id) {
const dataNotes = this.state.dataNotes.map((note) => {
if (note.id === id) {
return { ...note, archived: !note.archived };
} else {
return note;
}
});
this.setState({ dataNotes });
}
onSearchHandler(event) {
this.setState(() => {
return {
searchTitle: event.target.value,
};
});
}
render() {
console.log(this.state.dataNotes);
console.log(`search ${this.state.searchTitle}`);
const dataNotes = this.state.dataNotes.filter((note) =>
note.title.toLowerCase().includes(this.state.searchTitle.toLowerCase())
);
return (
<>
<HeaderPage
searchTitle={this.state.searchTitle}
onSearch={this.onSearchHandler}
></HeaderPage>
<Header
searchTitle={this.state.searchTitle}
onSearch={this.onSearchHandler}
></Header>
<MainPage
dataNotes={dataNotes}
addNote={this.onAddNoteHandler}
onDelete={this.onDeleteHandler}
onArchive={this.onArchivedHandler}
></MainPage>
<FooterPage></FooterPage>
</>
);
}
}
export default PageNote;

react Todo list "remove" function

i have tried to remove todo task from my state array but its not working for me. i am having hard time using deletHandle function in Todolist.js. how can i use key from state to indentify and delete clicked(or perticular) todo task
App.js
import React from 'react';
import { Form } from './components/todo-Form/Form.component';
import { Todolist } from './components/Todolist/Todolist.component';
import './App.css';
class App extends React.Component {
constructor() {
super();
this.state = {
todo: [],
do: ""
}
}
render() {
const handleChange = e => {
this.setState({ do: e.target.value }/*, () => { console.log(e) }*/);
};
const submitHandler = e => {
e.preventDefault();
if (this.state.do != "" ) {
this.setState({ todo: [...this.state.todo, { task: this.state.do, id: Math.random() * 1000 }], do: "" }/*, () => { console.log(this.state.todo) }*/)
}
}
const deletHandler = key => {
this.setState({
todo: this.state.todo.filter(el => el !== key)
})
}
return (
<div className="App">
<header>
<h1>ToDo List</h1>
</header>
<Form handleChange={handleChange} submitHandler={submitHandler} inputText={this.state.do} />
<Todolist check={this.state.todo} deletHandler={deletHandler}/>
</div>
)
}
}
export default App;
Todolist.js
import React from "react";
import { Todo } from "../Todo/Todo.component";
import "./todolist.style.css"
export const Todolist = ({check, deletHandler}) => {
return <div >
<ul className="todo-list">
{check.map(todo => (<Todo task={todo.task} key={todo.id} onClick={() => {deletHandler(todo.id)}}/>))}
</ul>
</div>;
};
Todo.js
import React from "react";
import "./todo.style.css";
export const Todo = ({task}) =>{
return (
<div className="todo-container" >
<li className="todo">
<h2> {task} </h2>
<ul className="delet-x">X</ul>
</li>
</div>)
}
In your delete handler, you have to use the id to delete
const deletHandler = (key) => {
this.setState({
todo: this.state.todo.filter((el) => el.id !== key),
});
};

Getting information about outcome of the class React

I am making project, where you get books cards using Google Books API. I need to count amount of books I get in the end and print in in Header.js(after search). I think I need to add new parameter like 'count' in constructor that will get books.length but still don't know how to pass it in the end.
Books.js
import React, { Component } from 'react';
import SearchArea from './SearchArea';
import request from 'superagent';
import BookList from './BookList';
class Books extends Component {
constructor(props){
super(props);
this.state = {
books: [],
searchField: '',
sort: ''
}
}
searchBook = (e) => {
e.preventDefault();
request
.get("https://www.googleapis.com/books/v1/volumes")
.query({ q: this.state.searchField })
.then((data) => {
console.log(data);
const cleanData = this.cleanData(data)
this.setState({ books: cleanData })
})
}
handleSearch = (e) => {
this.setState ({ searchField: e.target.value })
}
handleSort = (e) => {
console.log(e.target.value)
this.setState({sort: e.target.value})
}
cleanData = (data) => {
const cleanedData = data.body.items.map((book) => {
if(book.volumeInfo.hasOwnProperty('publishedDate') === false){
book.volumeInfo['publishedDate'] = '0000';
}
else if(book.volumeInfo.hasOwnProperty('imageLinks') === false) {
book.volumeInfo['imageLinks'] = {thumbnail: 'https://vignette.wikia.nocookie.net/pandorahearts/images/a/ad/Not_available.jpg/revision/latest?cb=20141028171337'}
}
console.log(this.state.books.length)
return book;
})
return cleanedData;
}
render(){
const sortedBooks = this.state.books.sort((a,b) => {
if(this.state.sort === 'Newest') {
return parseInt(b.volumeInfo.publishedDate.substring(0,4)) - parseInt(a.volumeInfo.publishedDate)
}
else if(this.state.sort === 'Oldest') {
return parseInt(a.volumeInfo.publishedDate.substring(0,4)) - parseInt(b.volumeInfo.publishedDate)
}
})
return (
<div>
<SearchArea searchBook = {this.searchBook} handleSearch={this.handleSearch} handleSort={this.handleSort}/>
<BookList books={this.state.books} />
</div>
);
}
}
export default Books;
SearchArea.js
import React from 'react'
const SearchArea = (props) => {
return(
<div className="search-area">
<form onSubmit={props.searchBook} action="">
<input onChange={props.handleSearch} type="text"/>
<button id="search" type="submit">Search</button>
<select defaultValue="Sort" onChange={props.handleSort}>
bled v<option disaalue="Sort">Sort</option>
<option value="Newest">Newest</option>
<option value="Oldest">Oldest</option>
</select>
</form>
</div>
)
}
export default SearchArea;
BookList.js
import React from 'react';
import BookCard from './BookCard';
const BookList = (props) => {
return(
<div className="list">
{
props.books.map((book,i) => {
return <BookCard
key={i}
image={book.volumeInfo.imageLinks.thumbnail}
title={book.volumeInfo.title}
author={book.volumeInfo.authors}
published={book.volumeInfo.publishedDate}
/>
})
}
</div>
)
}
export default BookList;
Header.js
import React from 'react';
const Header = () => {
return(
<header>
<h1>Book Cards</h1>
</header>
)
}
export default Header;

TypeError: this.props.* is not a function

I get this error in my code
TypeError: this.props.* is not a function
and i cannot figure it out what is wrong with it.
I have tried different approaches butt still gives me this error even if I "binded" the function to "this".
SingleCurPlaylist.js
import React from "react";
import "./SingleCurPlaylist.css";
class SingleCurPlaylist extends React.Component {
constructor(props) {
super(props);
this.showList = this.showList.bind(this);
}
showList() {
this.props.showList(this.props.id);
}
render() {
return (
<div className="Single-list" onClick={this.showList}>
<h4>{this.props.name}</h4>
</div>
);
}
}
export default SingleCurPlaylist;
PlayistSpotify.js
import React from "react";
import SingleCurPlaylist from "../SingleCurPlaylist/SingleCurPlaylist";
import "./PlaylistSpotify.css";
class PlaylistSpotify extends React.Component {
constructor(props) {
super(props);
this.renderList = this.renderList.bind(this);
}
renderList() {
this.props.getLocalPlaylists();
}
render() {
return (
<div className="PlaylistSpotify">
<h2>Local Playlists</h2>
<button className="Playlist-get" onClick={this.renderList}>
Get your local playlist
</button>
{this.props.playlistLists.map((singlePlay) => (
<SingleCurPlaylist
showList={this.props.showList}
id={singlePlay.id}
key={singlePlay.id}
name={singlePlay.name}
/>
))}
</div>
);
}
}
export default PlaylistSpotify;
This is App.js, where once the error is fixed "showList" is supposed to receive the playlist id
import React from "react";
import SearchBar from "../SearchBar/SearchBar";
import SearchResults from "../SearchResults/SearchResults";
import Playlist from "../Playlist/Playlist";
import Spotify from "../../util/Spotify";
import PlaylistSpotify from "../PlaylistSpotify/PlaylistSpotify";
import "./App.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchInput: "",
searchResults: [],
playlistName: "New Playlist",
playlistTracks: [],
localPlaylists: [],
};
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.removeTrack.bind(this);
this.updatePlaylistName = this.updatePlaylistName.bind(this);
this.savePlaylist = this.savePlaylist.bind(this);
this.search = this.search.bind(this);
this.getLocalPlaylists = this.getLocalPlaylists.bind(this);
}
addTrack(track) {
let newPlaylist = this.state.playlistTracks;
if (newPlaylist.find((playTrack) => playTrack.id === track.id)) {
return;
} else {
newPlaylist.push(track);
}
this.setState({ playlistTracks: newPlaylist });
}
showList(playlist) {
console.log(playlist);
}
removeTrack(track) {
let playlist = this.state.playlistTracks;
let newPlaylist = playlist.filter((playTrack) => playTrack.id !== track.id);
this.setState({ playlistTracks: newPlaylist });
}
updatePlaylistName(name) {
this.setState({ playlistName: name });
}
savePlaylist() {
const trackUris = this.state.playlistTracks.map((track) => track.uri);
Spotify.savePlaylist(this.state.playlistName, trackUris).then(() => {
this.setState({
playlistName: "New Playlist",
playlistTracks: [],
});
});
}
// keep search after url updated
componentDidMount() {
Spotify.getAccessToken();
}
getLocalPlaylists() {
Spotify.getPlaylist().then((playlistLists) => {
let newList = playlistLists.items.map((playlist) => {
return {
name: playlist.name,
id: playlist.id,
};
});
this.setState({ localPlaylists: newList });
});
}
search(term) {
Spotify.search(term).then((searchResults) => {
// filters results in order not to show tracks already in the playlist
searchResults = searchResults.filter((track) => {
return this.state.playlistTracks.every((el) => el.uri !== track.uri);
});
this.setState({ searchResults: searchResults, searchInput: term });
});
}
render() {
return (
<div>
<h1>
Ja<span className="highlight">mmm</span>ing
</h1>
<div className="App">
{<SearchBar onSearch={this.search} />}
<div className="App-playlist">
{
<SearchResults
searchResults={this.state.searchResults}
onAdd={this.addTrack}
/>
}
{
<Playlist
playlistName={this.state.playlistName}
playlistTracks={this.state.playlistTracks}
onRemove={this.removeTrack}
onNameChange={this.updatePlaylistName}
onSave={this.savePlaylist}
showList={this.showList}
/>
}
{
<PlaylistSpotify
getLocalPlaylists={this.getLocalPlaylists}
playlistLists={this.state.localPlaylists}
/>
}
</div>
</div>
</div>
);
}
}
export default App;
Thanks for your help!
You don't pass showList={this.showList} to PlaylistSpotify, so it is undefined when passing to SingleCurPlaylist and on.
<PlaylistSpotify
getLocalPlaylists={this.getLocalPlaylists}
playlistLists={this.state.localPlaylists}
showList={this.showList}
/>
in PlayistSpotify.js file, in the playlistLists loop, this.props.showList is unedfined:
{this.props.playlistLists.map((singlePlay) => (
<SingleCurPlaylist
showList={this.props.showList} // this is undefined
id={singlePlay.id}
key={singlePlay.id}
name={singlePlay.name}
/>
))}
because you're not passing it from App.js:
{<PlaylistSpotify
getLocalPlaylists={this.getLocalPlaylists}
playlistLists={this.state.localPlaylists}
//showList is not passed
/>
}

Why is my DeleteTodos function behaving so oddly in my TodoList App?

I am trying to build a simple todolist app on react and I came up this problem. I could write the code necessary for adding todo items to the list defined in the state and displaying it but when it comes to deleting items off of the list from the click of the button adjacent to every todoitem, all todoitems get removed from the list except the first item. what should I do. Here's the code :
The TodoList(parent) Component:
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
The DisplayTodos Component:
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
AddTodos Component
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
DeleteTodos = (i) => {
i.preventDefault();
let arr = [].concat(this.state.myList);
arr.splice(i, 1);
this.setState({myList: arr});
}
The splice function will change the array and return a new array of deleted items, so you should declair a variable to copy myList, and change the variable. What you do will change the state.

Categories