Why is onClick={this.onToggleMenuModal} not triggering on div id="freezer", whilst it is in my components by passing onToggleMenuModal={this.handleToggleMenuModal}?
Adding onToggleMenuModal={this.handleToggleMenuModal} to returned an error of Unknown Prop Warning
Here is the code...
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template
You must put onClick inside arrow fuction like :
onClick={() => {this.onToggleMenuModal}}
Check this solution and let me know if it work for you or not.
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template
Related
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;
How we can change the handlerOnMouseMove inside other handler (in my example OnClick).
I show an example below;
normally when I do this this.handleMouseMove = undefined; it should disable my event onMouseMove but unfortunately it is not working.
import React from 'react'
import {render} from 'react-dom'
import './BasicComponent.css'
class BasicComponent extends React.Component {
constructor (props){
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.handleClick = this.handleClick.bind(this)
this.handleMouseDown = this.handleMouseDown.bind(this)
this.handleMouseUp = this.handleMouseUp.bind(this)
this.handleMouseMove = this.handleMouseMove.bind(this)
}
render() {
console.log("render");
return(
<div className="component"
onMouseDown={ this.handleMouseDown }
onMouseUp={ this.handleMouseUp }
onMouseMove={ this.handleMouseMove }>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={ this.handleClick } >Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.handleMouseMove = undefined; // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown() {
console.log("handleMouseDown");
}
handleMouseUp() {
console.log("handleMouseUp");
}
handleMouseMove() {
console.log("handleMouseMove");
}
}
export default BasicComponent
Try this:
class BasicComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
disableMouseMove: false,
};
this.handleClick = this.handleClick.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
}
render() {
const { disableMouseMove } = this.state;
return (
<div
className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={disableMouseMove ? () => {} : this.handleMouseMove}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick}>Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.setState({ disableMouseMove: true }); // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
}
You can createRef for the wrapper div you are tracking the "mousemove", add the "mousemove" event listener for that ref once component mounts and remove it once the button is clicked. Hint, there is no more "onMouseMove" for the wrapping div. Below I also replaced your class methods with arrow functions in order to avoid binding them.
export default class BasicComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.myRef = React.createRef()
}
componentDidMount(){
this.myRef.current.addEventListener('mousemove', this.handleMouseMove)
}
handleClick = () => {
this.myRef.current.removeEventListener('mousemove', this.handleMouseMove)
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown = () => {
console.log("handleMouseDown");
}
handleMouseUp = () => {
console.log("handleMouseUp");
}
handleMouseMove = () => {
console.log("handleMouseMove");
}
render() {
console.log("render");
return (
<div ref={this.myRef} className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick} >Disable handler
onMouseMove
</button>
</div>
);
}
}
I want to hide some component based on some flag in react js.
I have an App component where I have Login and other components, I want to hide the other component until Login components this.state.success is false and on click of a button I am changing the sate, but it's not working, I am new to react,
My App Class compoenent -
import React, { Component } from "react";
import logo from "../../logo.svg";
// import Game from "../Game/Game";
import Table from "../Table/Table";
import Form from "../Table/Form";
import Clock from "../Clock/Clock";
import "./App.css";
import Login from "../Login/Login";
class App extends Component {
state = {
success: false
};
removeCharacter = index => {
const { characters } = this.state;
this.setState({
characters: characters.filter((character, i) => {
return i !== index;
})
});
};
handleSubmit = character => {
this.setState({ characters: [...this.state.characters, character] });
};
handleSuccess() {
this.setState({ success: true });
}
render() {
const { characters, success } = this.state;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<span className="Span-inline">App</span>
<Clock time={new Date()} />
</header>
<Login success={success} handleSuccess={this.handleSuccess} />
{success && (
<div className="container">
<h1>React Tutorial</h1>
<p>Add a character with a name and a job to the table.</p>
<Table
characterData={characters}
removeCharacter={this.removeCharacter}
/>
<h3>Add New character</h3>
<Form handleSubmit={this.handleSubmit} />
</div>
)}
{/* <Game /> */}
</div>
);
}
}
export default App;
My Login component -
import React, { Component } from "react";
import Greeting from "./Greeting";
import LogoutButton from "./LogoutButton";
import LoginButton from "./LoginButton";
class Login extends Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {
isLoggedIn: false,
name: "",
success: false
};
}
handleLoginClick() {
this.setState({ isLoggedIn: true });
this.setState({ success: true });
}
handleLogoutClick() {
this.setState({ isLoggedIn: false });
this.setState({ success: false });
}
onChange = e => {
this.setState({
name: e.target.value
});
};
render() {
const isLoggedIn = this.state.isLoggedIn;
const name = this.state.name;
// const successLogin = this.state.success;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting
isLoggedIn={isLoggedIn}
name={name}
onChange={this.onChange}
/>
{button}
</div>
);
}
}
export default Login;
please guide me on what I am doing wrong.
Why sometime debuggers do not trigger in react component?
For the sake of example I have used functional stateless component here. You can use Class component all upto you.
const conditionalComponent = (props) => {
let condition = true;
return (
{condition && <div><h1>Hello world</h1></div>}
}
Instead of directly giving condition you can even call function which returns a boolean value.
handleLoginClick() {
this.setState({ isLoggedIn: true });
this.setState({ success: true });
this.props.handleSuccess()
}
do like this
<Login success={success} handleSuccess=
{this.handleSuccess} />
bind this function
I am passing the state of the parent component from the parent component to the child component.And in the child component,I have a different state.I am performing some actions on the child component's state and the result of that has to be added to the parent component's state.So,in my parent component I have written a callback function which will update the state of the parent component.The code is:
updateState = (booksList) => {
this.setState({books : this.state.books.push(booksList)});
}
So,this function is then passed to the child component as props:
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
Then in my child component,I am trying to implement the callback function as :
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
But this is not working as expected.Is this the correct way?Can anyone please help me with this?
I have tried to solve my problem by implementing the solution provided here : How to pass data from child component to its parent in ReactJS? , but I am getting some errors.
EDIT
Parent component : App.js
import React from 'react'
import * as BooksAPI from './BooksAPI'
import { Link } from 'react-router-dom'
import { Route } from 'react-router-dom'
import './App.css'
import BookList from './BookList'
import BookSearch from './BookSearch'
class BooksApp extends React.Component {
constructor(props) {
super(props);
this.state = {
books: [],
showSearchPage : false
};
//this.updateState = this.updateState.bind(this)
}
componentDidMount() {
BooksAPI.getAll().then((books) => {
this.setState({ books })
})
console.log(this.state.books);
}
filterByShelf = (bookName,shelfName) =>
bookName.filter(book => book.shelf===shelfName)
isTheBookNew = book => {
let is = false;
if (book.shelf === "none")
{ this.setState(state =>
{
books: state.books.push(book)});
is = true;
console.log(this.state.books);
}
return is;
};
handleShelfChange = (bookOnChange, newSehlf) => {
!this.isTheBookNew(bookOnChange) && this.setState(state => {
let newBooks = state.books.map(book =>
{ if (bookOnChange.id === book.id)
{ book.shelf = newSehlf; }
return book;
});
return {
books: newBooks
};
}
);
BooksAPI.update(bookOnChange, newSehlf);
};
updateState = (booksList) => {
const books = [...this.state.books, booksList]
this.setState({ books });
}
render() {
return (
<div className="app">
<Route exact path="/" render={() => (
<div className="list-books">
<div className="list-books-title">
<h1>MyReads</h1>
</div>
<BookList
books={this.filterByShelf(this.state.books,'currentlyReading')}
shelfName='Currently Reading'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'wantToRead')}
shelfName='Want to Read'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'read')}
shelfName='Read'
handleShelfChange={this.handleShelfChange}/>
<div className="open-search">
<Link
to="./search" />
</div>
</div>
)
} />
<Route path="/search" render={() =>
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
} />
</div>
)
}
}
export default BooksApp
BookSearch.js :
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import escapeRegExp from 'escape-string-regexp'
import sortBy from 'sort-by'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'
class BookSearch extends Component {
constructor(props) {
super(props);
this.state = {
search:'',
books:[]
}
}
updateSearch = (searchString) => {
this.setState({search: searchString.trim()})
let searchResults = BooksAPI.search(this.state.search,1).then((book_search) => {
if (book_search != undefined) {
console.log(book_search);
book_search.map((book) => book.shelf = 'none');
this.setState({ books : book_search }, this.check); // callback function to this.setState
console.log(this.state.books)
}
})
}
check = () => {
let parent_books = this.props.books;
console.log(this.state.books)
const book_result = this.state.books.map((book) => {
const parent = parent_books.find(parent => parent.title === book.title );
if(parent) {
//console.log(parent);
book.shelf = parent.shelf;
//console.log(book)
}
return book;
})
this.setState({books: book_result}, () => {console.log(this.state.books)})
}
updateParentState = () => {
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
}
render() {
return(
<div className="search-books">
<div className="search-books-bar">
<Link
to="/"
className="close-search">
Close
</Link>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title or author"
value={this.state.search}
onChange={(event) => this.updateSearch(event.target.value)}/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
<BookList
books={this.state.books}
handleShelfChange={this.props.handleShelfChange}
updateParentState={this.updateParentState}/>
</ol>
</div>
</div>
)
}
}
export default BookSearch
BookList.js
import React, { Component } from 'react';
import Book from './Book'
class BookList extends Component {
constructor(props) {
super(props);
this.state = {
showSearchPage : false
}
console.log(this.props.books)
}
render() {
return(
<div className="app">
<div>
<div className="list-books-content">
<div>
<div className="bookshelf">
<h2 className="bookshelf-title">{this.props.shelfName}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{this.props.books.map(book =>
<li key={book.title}>
<Book
book={book}
handleShelfChange={this.props.handleShelfChange}
update={this.props.updateParentState} />
</li>)
}
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default BookList;
Book.js
import React, { Component } from 'react'
class Book extends Component {
constructor(props) {
super(props);
this.props.updateParentState;
}
render() {
return(
<div className="book">
<div key={this.props.book.title}>
<div className="book-top">
<div className="book-cover" style={{width:128, height:193, backgroundImage: `url(${this.props.book.imageLinks.thumbnail})`}}>
<div className="book-shelf-changer">
<select id="bookName" value={this.props.book.shelf}
onChange={(event) => this.props.handleShelfChange(this.props.book, event.target.value)}>
<option value="moveTo" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>
</div>
</div>
</div>
<div className="book-title">{this.props.book.title}</div>
<div className="book-authors">{this.props.book.authors}</div>
</div>
</div>
)
}
}
export default Book
So, I have 4 components as shown above.From App component,I am calling BookSearch component where I can search for books and send the books to App component by selecting the value in dropdown. Each book in BookSearch component will initially be assigned a shelf property of "none".When a user selects a shelf value from Booksearch,the book will automatically be added to the App component.So,when I navigate back to the App component from BookSearch,I should be able to see the book in the assigned shelf.So,for this case,I am using the updateSearch function. The books are displayed through the Book component which has the dropdown value.
If i understood this correctly, you are mutating the state in the function updateState.
What you should be doing instead is,
const updateState = (booksList) => {
const books = [ ...this.state.books, ...booklist ];
this.setState({ books });
}
In parent component constructor add the following line:
this.updateState = this.updateState.bind(this)
More at https://reactjs.org/docs/handling-events.html
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.