ReactJS: Cannot read property 'bind' of undefined - reactjs

I'm tried to figure out How can I have these two buttons the Login and Sign up that will be toggling the Login and Sign up box back in forward.
I couldn't figure out.... Does anyone can solve this?
this is my code. I'd like to call "selected-controller" method from div item. But then, Cannot read property 'bind' of undefined.
Navigation.js
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import "../components/pages/Forms/MainScreen";
import Dropdown from "../components//pages/dropdowns/dropdowns";
import hamburger from "../images/menu.svg";
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
e.preventDefault();
this.setState(prevState => ({
isExpanded: !prevState.isExpanded, // negate the previous expanded state
}));
}
render() {
const { isExpanded } = this.state;
return (
<Router>
<div className="NavbarContainer">
<div className="mobilecontainer LeftNav">
<h2 className="BrandName LeftNav mobileboxmenu inline FarRight">Kommonplaces</h2>
<div className="hamburger inlinev" >
<img
onClick={e => this.handleToggle(e)}
alt="menubtn"
src={hamburger}
/>
</div>
</div>
<ul className={`NavBar collapsed ${isExpanded ? "is-expanded" : ""}`}>
<Dropdown/>
<li className="RightNav"><Link to="/">Host Your Space</Link></li>
<li className="RightNav"><Link to="/">About Us</Link></li>
<li className="RightNav"><Link to="/">Contact Us</Link></li>
<div className="btnflexright">
<div
className={"controller " + (this.state.isLoginOpen
? "selected-controller"
: "")}
onClick={this
.showLoginBox
.bind(this)}>
Login
</div>
<div
className={"controller " + (this.state.isRegisterOpen
? "selected-controller"
: "")}
onClick={this
.showRegisterBox
.bind(this)}>
Sign up
</div>
</div>
</ul>
</div>
</Router>
);
}
}
export default Navigation;
This is the main screen where the login and Sign form will go:
import React from 'react';
import RegisterBox from '../Forms/Register'
import LoginBox from '../Forms/Register'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoginOpen: true,
isRegisterOpen: false
};
}
showLoginBox() {
this.setState({isLoginOpen: true, isRegisterOpen: false});
}
showRegisterBox() {
this.setState({isRegisterOpen: true, isLoginOpen: false});
}
render() {
return (
<div>
<div className="root-container">
{this.state.isLoginOpen && <LoginBox/>}
{this.state.isRegisterOpen && <RegisterBox/>}
</div>
</div>
)
}
}
export default App;
Login and Sign up Form are the same but in two different files Login.js and Register,js I will show the code for that one now.
//Login Box
import React from 'react';
class LoginBox extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<div className="formContent modal-main">
<h2>Welcome Back <span>Brandon!</span></h2>
<form>
<input
type="text"
name="email"
placeholder="Email Address"
/>
<input
name="password"
type="text"
placeholder="Password"
/>
<div className="passContent">
<div className="checkingPass">
<input
className="inline"
type="checkbox"
name="check"
value="Remember Password"
/>
<span
className="inline">
Remember Password
</span>
</div>
<p
className="passFont">
Forgot Password
</p>
</div>
<input
className="formmbtn"
type="button"
name="button"
alue="Login"
/>
<div
className="social-media-button">
<input
className="clearbtn"
type="button"
name="button"
value="Sign in with Facebook"
/>
<div
className="divider"
/>
<input
className="clearbtn"
type="button"
name="button"
value="Sign in with Facebook"
/>
</div>
<p
className="passFont">
Don't have an account?
<span>Sign up</span>
</p>
</form>
</div>
</div>
)
}
}
export default LoginBox;

The class Navigation doesn't have the functions showRegisterBox and showLoginBox, so this.showRegisterBox is undefined (that's why you get the Cannot read property 'bind' of undefined error when you do this.showRegisterBox.bind() on the Navigation Component.
Possible solutions:
If those functions aren't defined in the Navigation component, then you should probably pass them as props when you instantiate Navigation. That's the usual way a component communicates with it's parent component.
So if for example you were to use your Navigation component in App (which is where those functions are defined), you would do:
<Navigation showRegisterBox={this.showRegisterBox.bind(this)} showLoginBox={this.showLoginBox.bind(this)}/>
Then in Navigation you use them like such:
onClick={this.props.showRegisterBox}

Related

How to manage the state using Redux

I'm working on a project, I'm using Django as backend, React as frontend and Redux as state manager. I want to pass a function from my login and register component to my Header component, whereas my header component is not a root component I can't pass params directly to other components. I know redux can solve this problem but I don't know how?
I have two separate links in my header component (Login, Register), I mean when I click on login it should call the openLoginModal() from my login component and the same process for register component
My header component
import React, { Component, Fragment } from "react";
import { Link } from "react-router-dom";
export class Header extends Component {
render() {
return (
<Fragment>
<nav className="navbar navbar-expand-sm ">
<div className="container">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarTogglerDemo01"
aria-controls="navbarTogglerDemo01"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarTogglerDemo01">
<a className="navbar-brand" href="/">
Todos
</a>
<ul className="navbar-nav ml-auto mt-2 mt-lg-0">
<Link to="/register">
<button className="btn btn-outline-primary btn-sm mx-2">
Register
</button>
</Link>
<Link to="/login">
<button className="btn btn-outline-primary btn-sm">
Login
</button>
</Link>
</ul>
</div>
</div>
</nav>
</Fragment>
);
}
}
export default Header;
I also used react-awesome-modal for creating login and register modal, here is my login component
import React, { Component, Fragment } from "react";
export class Login extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
username: "",
password: "",
};
}
openLoginModal() {
this.setState({
visible: true,
});
}
closeLoginModal() {
this.setState({
visible: false,
});
}
render() {
const { username, password } = this.state;
return (
<Fragment>
<section>
<Modal
visible={this.state.visible}
width="400"
height="300"
effect="fadeInUp"
onClickAway={() => this.closeLoginModal()}
>
<div>
<form>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
value={username}
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
value={password}
/>
</div>
<div className="form-group">
<button className="btn btn-primary btn-sm my-2">Login</button>
</div>
</form>
</div>
</Modal>
</section>
</Fragment>
);
}
}
export default Login;
Just only store variable isOpenModal into the state of redux and add 2 action creator
openModal() {
return { type: 'OPEN_MODAL' }
}
closeModal {
return { type: 'CLOSE_MODAL'
}
change state through reducers (file reducers)
// another code
switch(action.type) {
case 'OPEN_MODAL':
state.isOpenModal = true;
break;
case 'CLOSE_MODAL':
state.isOpenModal = false;
break;
// another code
}
In file Header use mapDispatchToProps to call 2 action creator openModal and closeModal as created above.
In file Login use mapStateToProps to use state isOpenModal in state of redux.

Reactjs not able to render a component which has a form

In my App.js, I have a class component Addition which will display 2 numbers and have a text box to get the result from the user. In the same file I have another class component App from which when I try to call <Addition/>, it renders the form perfectly as expected. However, I want the <Addition/> component to be triggered on a button click, which is not working.
class Addition extends Component{
render(){
return (
<form onSubmit={this.validateResult}>
<div >
<Box1 val={this.state.value1}/>
<Box1 val="+"/>
<Box1 val={this.state.value2}/>
<Box1 val="=" />
<input className="resbox"
value={this.state.result}
onChange={event => this.setState({result: event.target.value})}
required
/>
<br/>
<Box2 val={this.state.message} />
<br/><br/>
<input className="btn btn-info" type="submit" value="Submit" />
</div>
</form>
)
}
}
export default class App extends Component {
handleClick= (event) => {
event.preventDefault()
console.log("inside handleclick")
return (
<Addition />
);
}
render(){
return (
<div className="App">
<header className="row App-header">
<p >
KIDS MATHS
</p>
<div className="row col-2">
<button className="btn btn-lg offset-1" onClick={this.handleClick}> + </button>
</div>
</header>
</div>
)
}
}
When I tried to include the <Addition/> within the on-click event, the page simply remains same.
Please advice.
Everything you want to render has to called directly from within the render function. You can use conditional rendering to achieve to selective rendering of Addition. For this add a state member and set the value accordingly at the trigger point. This will call render again and the content will be shown as expected.
export default class App extends Component {
state = {
showAddition: false
}
handleClick= (event) => {
event.preventDefault()
console.log("inside handleclick")
this.setState({showAddition: true})
}
render(){
const { showAddition } = this.state
return (
<div className="App">
<header className="row App-header">
<p >
KIDS MATHS
</p>
<div className="row col-2">
<button className="btn btn-lg offset-1" onClick={this.handleClick}> + </button>
</div>
</header>
{showAddition && <Addition/>}
</div>
)
}
}
You can also consider to convert the components to function components and use useState instead of the state object. This will shorten the code a little bit.

React-Redux Application: 'props' is not defined'

I am creating a React-Redux application. Before adding the content above render(), props was defined. However, after I started adding said content, the app began having problems reading the variable. I don't know what happened.
Could somebody please help me understand why props isn't being recognized anymore? I'd really appreciate it.
Login.js
import React from 'react';
import Modal from 'react-bootstrap/Modal';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import './login.css';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
this.onChange = this.onChange.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value});
}
render() {
return (
<>
<Modal show={props.modalOpen} onHide={props.handleModalOpen}>
<Modal.Header closeButton>
<Modal.Title>Login</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group>
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
name="username"
className="form-control"
/>
</Form.Group>
<Form.Group>
<Form.Label>Password</Form.Label>
<Form.Control
type="text"
name="password"
className="form-control"
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" type="submit" onClick={props.handleModalOpen}>
Submit
</Button>
<Button variant="primary" onClick={props.handleClose}>
Cancel
</Button>
</Modal.Footer>
</Modal>
</>
);
}
}
export default LoginForm;
Navbar.js
import React from "react";
import { Link } from 'react-router-dom';
import './navbar.css';
import LoginForm from '../LoginForm/login.js';
// import SignUpModal from '../SignUpModal/signup.js';
class Navbar extends React.Component {
state = {
modalOpen: false
}
handleModalOpen = () => {
this.setState((prevState) => {
return {
modalOpen: !prevState.modalOpen
}
})
}
render() {
return (
<div>
<nav className="navbar navbar-expand-sm navbar-dark px-sm-5">
<div className="container">
<Link to='/'>
<div className="navbar-brand">
<i class="fas fa-globe fa-2x"></i>
</div>
</Link>
<ul className="navbar-nav align-items-right">
<li className="nav-item ml-5">
<a onClick={this.handleModalOpen} className="nav-link">
Login
</a>
</li>
<li className="nav-item ml-5">
<a onClick={this.handleModalOpen} className="nav-link">
Sign Up
</a>
</li>
</ul>
</div>
</nav>
<LoginForm
modalOpen={this.state.modalOpen}
handleModalOpen={this.handleModalOpen}
/>
{/* <SignUpModal
modalOpen={this.state.modalOpen}
handleModalOpen={this.handleModalOpen}
/> */}
</div>
)
}
}
export default Navbar;
In your Login.js, it's written using class-based syntax, hence it has to be this.props instead of props
<Modal show={this.props.modalOpen} onHide={this.props.handleModalOpen}>
Alternatively, Login.js can be rewrite into functional-based component, you can then use props like below
const Login = props => {
return (
<Modal show={props.modalOpen} onHide={props.handleModalOpen} />
)
}

Why isn't mapDispatchToProps being called after linking to my component?

I have a component that looks like this (/Inputs/AddPersonForm):
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
import { addPerson } from '../Actions/personActions';
import { Person } from '../Components/Person'
export class AddPersonForm extends Component {
constructor(props) {
super(props)
this.state = {
//TODO initialize name to value that was just searched for to make UI
cleaner
name: '',
description: '',
location:'',
}
}
handleOnChange = event => {
const { value, name } = event.target;
this.setState({
[name]: value,
});
}
handleOnSubmit = event => {
const person = Object.assign({}, this.state);
event.preventDefault();
//mapdispatchtoprops not working when linking to this component
this.props.addPerson(person);
this.setState({
name: '',
description: '',
location:'',
});
}
componentDidMount() {
alert("The person you are searching for does not yet exist in our
system. Please add their name, a physical description, and their city,
state, and zip code.")
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="panel panel-default">
<div className="panel-body">
<form className="form-horizontal" onSubmit={this.handleOnSubmit}>
<div className="form-group">
<label htmlFor="name" className="col-md-4 control-label">Person's Name</label>
<div className="col-md-5">
<input
className="form-control"
name="name"
value={this.state.name}
onChange={this.handleOnChange}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="description" className="col-md-4 control-label">Physical Description</label>
<div className="col-md-5">
<textarea
className="form-control"
name="description"
value={this.state.description}
onChange={this.handleOnChange}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="location" className="col-md-4 control-label">Location</label>
<div className="col-md-5">
<input
className="form-control"
type="text"
name="location"
value={this.state.location}
onChange={this.handleOnChange}
/>
</div>
</div>
<div className="form-group">
<div className="col-md-6 col-md-offset-4">
<button type="submit" className="btn btn-default">Add Person to Archive</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
const mapDispatchToProps = () => {
debugger;
return {
addPerson: addPerson
};
};
export default connect(null, mapDispatchToProps)(AddPersonForm);
I have a redirect to the that component and a link to it from this component (/Components/Person):
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { AddPersonForm } from '../Inputs/AddPersonForm';
import AddReviewForm from '../Inputs/AddReviewForm';
import { FormattedPerson } from '../Presentational/FormattedPerson';
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
Switch
} from "react-router-dom";
export class Person extends Component {
render() {
if (this.props.person == "unfound") {
return (
<div>
{this.props.history.push('/add-person')}
</div>
)
} else {
return (
<div>
<div className= "container">
<Router>
<div>
<Link to={`${this.props.match.url}/reviews/new`}>
Add a New Review for this Person
</Link><br />
<Link to='/add-person'
>Not the {this.props.person.name} you were looking for? Add them to our system!
</Link>
<div>
<Switch>
<Route path={`${this.props.match.url}/reviews/new`}
component={AddReviewForm} />
<Route path='/add-person' component={AddPersonForm}/>
</Switch>
</div>
</div>
</Router>
</div>
<FormattedPerson name= {this.props.person.name} description= {this.props.person.description} location= {this.props.person.location} reviews= {this.props.person.reviews}
/>
</div>
);
}
}
}
function mapStateToProps(state){
return {person: state.peopleReducer.person}
}
export default connect(mapStateToProps, null)(Person);
When I navigate via the redirect, everything works fine, mapDispatchToProps is called, and I can submit the form. But when I navigate via the link, mapDispatchToProps is not called, so when I try to submit the form, I get an error saying "this.props.addPerson is not a function". Why is this happening?
You have two exports, one at the first line and one at the last one. Remove the first.

How to change the state of an item affected by onClick in array?

I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.

Resources