React: Props are not being passed to children - reactjs

So I have this parent which clone and injects props Login to the children:
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import { NavMenu } from '../navigations/NavMenu';
import { Login } from './account/Login';
export class Layout extends Component {
static displayName = Layout.name;
render() {
const loginForm = new Login();
const childrenWithProps = React.Children.map(this.props.children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { loginForm: loginForm });
}
return child;
});
return (
<div>
{loginForm.render()}
<NavMenu />
<Container>
{childrenWithProps}
</Container>
</div>
);
}
}
This is one of the children:
import React, { Component } from 'react';
import { http } from '../../helpers/Http';
export class FetchData extends Component {
static displayName = FetchData.name;
constructor(props) {
super(props);
this.state = { forecasts: [], loading: true };
let x = this.props.loginForm; <-- THIS IS UNDEFINED
}
.......
}
The this.props.loginForm is undefined. How can I inject props correctly?
EDIT
This is the Login component:
import React, { Component } from 'react';
import './Login.css';
export class Login extends Component {
constructor(props) {
super(props);
this.state = { show: false };
this.login = this.login.bind(this);
this.showLogin = this.showLogin.bind(this);
}
showLogin() {
this.setState({
show: true
});
}
login() {
}
render() {
return (
<form className={this.state.show ? "login-form " : "login-form hide"} onSubmit={this.login()}>
<h1>Login</h1>
<div className="form-group">
<input required type="text" placeholder="Email" />
<input required type="password" placeholder="Password" />
</div>
<button type="submit" className="btn btn-primary">Login</button>
</form>
);
}
}
I want to call showLogin() from FetchData. If the user is not authorized when fetching the data, I want to show the login modal.

Related

Creating a simple todolist using React Js.Dont know why my state is not getting updated with new todo Item

I basically making a todolist app.I just want the user entered text and add it to my state.But when i click the button the state is not getting updated with the new todoItem.please help with this.
My state is in Context.js
import React from 'react';
const Context=React.createContext();
const reducer=(state,action)=>{
switch(action.type){
case "ADD_TODO":
return {
...state,
todos:[action.payload,...state.todos]
}
default:
return state;
}
}
export class Provider extends React.Component{
state={
todos:[
{id:"1",todoItem:"Code daily"},
{id:"2",todoItem:"play"},
{id: '16a1c935-a033-4272-85b4-4412de42b59f', todoItem: 'wdwdwd'},
],
dispatch:action=>{
this.setState(state=>{
reducer(state,action)
})
}
}
render(){
return(
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer=Context.Consumer;
My Input Component for taking the todoitem input from user and add it to the state.But my page is reloading but my user entered text is not added to the state.And there is no error showing.
InputTodo.js
import React, { Component } from 'react';
import '../css/InputTodo.css';
import { v4 as uuidv4 } from 'uuid';
import {Consumer} from '../context';
class InputTodo extends Component {
constructor(props){
super(props);
this.state={
inputValue:""
};
}
OnChange(event){
const txtEntered=event.target.value;
this.setState({
inputValue:txtEntered,
});
}
handleButtonClicked=(dispatch,event)=> {
event.preventDefault();
const inputValue=this.state.inputValue;
const newTodo={
id:uuidv4(),
todoItem:inputValue,
}
dispatch({type:'ADD_TODO',payload:newTodo});
this.setState({
inputValue:"",
});
this.props.history.push('/');
}
render() {
return(
<Consumer>
{value=>{
const {dispatch}=value;
return (
<form onSubmit={this.handleButtonClicked.bind(this,dispatch)}>
<div className="form-group">
<input value={this.state.inputValue} onChange={this.OnChange.bind(this)} className="form-control" placeholder="Enter the todo" />
<button type="submit" className="btn btn-primary">Add</button>
</div>
</form>
)}}
</Consumer>
)
}
}
export default InputTodo;
You just forgot to return the new state in dispatch setState:
export class Provider extends React.Component{
state={
/* ... */
dispatch:action=>{
this.setState(state=>{
return reducer(state,action) /* <--- Here you missed the return */
})
}
}
/* ... */

TypeError: this.props.changeUser is not a function

I am new in React Js and want to call the parent method from the child method.
There is a class login.jsx when someone clicks on submits button then a method changeUser in FirstPage.jsx should be invoked but when I try the online solution I am getting same error again and again that this.props.changeUser is not a function.
Login.jsx (child class)
import React, { Component } from 'react';
class Login extends Component {
constructor(props){
super(props);
this.state ={
user : null
}
this.onNameChange = this.onNameChange.bind(this);
this.onHandleClick = this.onHandleClick.bind(this);
}
onNameChange = (event)=>{
this.setState({
user:event.target.value
})
}
onHandleClick=(event)=>{
event.preventDefault();
this.props.changeUser("hello");
}
render() {
return (
<form>
<h3>Sign In</h3>
<div>
<label>User Name</label>
<input type="text" name="userId" placeholder="Enter User name" onChange ={this.onNameChange}/>
</div>
<button className="btn btn-primary btn-block" onClick={this.onHandleClick}>Submit</button>
</form>
);
}
}
export default Login;
FirstPage.jsx (parent class)
import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser =(x)=>{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage;import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser =(x)=>{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage;
I am getting an error that TypeError: this.props.changeUser is not a function
Please help me.
try to avoid using a lambda expression within you class component. Just create a simple member function:
import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser(x) // Try to declare this as member function
{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage
You are making a mistake here while binding , inside constructor
//WRONG
this.onNameChange = this.onNameChange.bind(this);
this.onHandleClick = this.onHandleClick.bind(this);
//RIGHT
this.onNameChange = onNameChange.bind(this);
this.onHandleClick = onHandleClick.bind(this);
CODE:
constructor(props){
super(props);
this.state ={
user : null
}
this.onNameChange = onNameChange.bind(this);
this.onHandleClick = onHandleClick.bind(this);
}

React input element's onChange using setState() doesn't work

I want to make an app so that when text is typed in input element this will reflect that change in output. So far the updating doesn't work :(
import React, { Component } from 'react';
import './App.css';
import UserInput from './UserInput/UserInput';
import UserOutput from './UserOutput/UserOutput';
class App extends Component {
state = {
user: [
{ username: 'Kai' },
{ username: 'Orange' }
]
}
inputChangeHandler = (e) => {
this.setState(
{
user: [
{ username: e.target.value },
{ username: e.target.value }
]
}
)
}
render() {
return (
<div className="App">
<UserInput onChange={this.inputChangeHandler} />
<UserOutput username={this.state.user[0].username} />
<UserOutput username={this.state.user[1].username} />
</div>
);
}
}
export default App;
Change in text typed in input element should be reflected as username rendered in UserOutput. This doesn't work.
Here are codes for other components...
import React, { Component } from 'react';
class UserInput extends Component
{
render() {
return(
<div>
<input />
</div>
);
}
}
export default UserInput;
and
import React, { Component } from 'react';
class UserOutput extends Component
{
render() {
return(
<div>
<p>First paragraph and my name is {this.props.username}</p>
<p>Second paragraph </p>
</div>
);
}
}
export default UserOutput;
Ok there's your problem. You're not assigning the change handler to the input element in your UserInput component. It should be:
<input onChange={this.props.onChange} />

react: access value of input component

I have build an input-field component and need to access its value from parent component. I tried something like document.getelementById(id).value, but it'll return null as value.
Parent component:
import StateBox from './StateBox.js';
import React, { Component } from 'react';
export default class AdressenListe extends Component {
render() {
let filteredAdressen = this.props.adressen.filter(
(asingle) => {
return asingle.Firma.toLowerCase().indexOf(document.getElementById('Firma').value.toLowerCase()) !== -1;
}
);
var anzahl = filteredAdressen.length;
return (
<div>
<StateBox id="Firma" />
<StateBox id="PLZ" />
<li>
</li>
</div>
);
}
}
Input-field component:
import React, {Component} from 'react';
export default class StateBox extends Component {
//constructor input field
constructor() {
super();
//equal to object
this.state = {
search: ''
};
}
updateSearch(event) {
console.log(event.target.value);
this.setState({search: event.target.value});
}
render(){
return(
<form className="StateBox">
<input type="text" value={this.state.search} onChange={this.updateSearch.bind(this)}/>
</form>
);
}
}
You can declare the state in the parent component and pass function to update that in child component
class Parent extends Component {
this.state = {
value: ''
}
changeValue = (value) => {
this.setState({value});
}
render() {
return <Child inputValue={this.state.value} changeValue={this.state.changeValue} />
}
}
class Child extends Component {
render() {
<input value={this.props.inputValue} onChange={(e) => this.props.changeValue(e.target.value)} />
}
}
If you want to access the value of a child component, you need to lift the state up and make the child component controlled, because that's the way you should code in react.
Taking your code as base:
class AdressenListe extends Component {
constructor() {
super();
this.state = {
Firma: ''
};
}
changeValue (Firma) {
this.setState({Firma});
}
render() {
let filteredAdressen = this.props.adressen.filter(
(asingle) => {
return asingle.Firma.toLowerCase().indexOf(this.state.Firma.toLowerCase()) !== -1;
}
);
return (
<div>
<StateBox inputValue={this.state.Firma} changeValue={this.changeValue.bind(this)} />
</div>
);
}
}
Note how I pass down the necessary props and the state is managed by the parent.
class StateBox extends Component {
render () {
return <input type="text" value={this.props.inputValue} onChange={(e) => this.props.changeValue(e.target.value)} />
}
}

Redirect doesn't work in React Router

So I am trying to make simple app with login form on the home page, which redirects then to dashboard. I faced a problem when trying to make /dashboard page private. Here is the code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {Redirect} from 'react-router-dom'
class DashBoard extends Component {
constructor(props) {
super(props);
}
render() {
if (this.props.auth.token) {
return (
<h2>Here will be dashboard with items.</h2>
);
} else {
return <Redirect to={{pathname: '/'}} push/>
}
}
}
export default connect(
(state) => {
return state;
}
)(DashBoard);
The problem is that url changes, but component does not actually render itself. So why redirect in dashboard doesnt work?
EDIT: I finally managed to make a redirect from Home component, but doing the same for dashboard still doesnt work!
import React, {Component} from 'react';
import {connect} from 'react-redux';
import * as actions from 'actions';
import {Redirect} from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentWillReceiveProps(nextProps) {
console.log('nextProps');
if (!nextProps.isLoading) {
if (nextProps.auth.error) {
console.log('error');
} else if (nextProps.auth.token) {
console.log('success');
} else {
console.log('something else');
}
}
}
handleSubmit(e) {
let {isLoading, auth, dispatch} = this.props
e.preventDefault();
let email = this.refs.email.value;
let password = this.refs.password.value;
dispatch(actions.login(email, password))
}
render() {
let {isLoading, auth} = this.props;
let renderLoading = () => {
if (isLoading) {
return 'Loading...'
} else {
return 'Submit';
}
}
let renderMessage = () => {
if (auth.error) {
return <p className="error-message">{auth.error}</p>;
} else if (auth.token) {
return <p className="success-message">You have successfully logined in.</p>
} else {
return <p></p>
}
}
if (auth.token) {
return (<Redirect to='/dashboard'/>)
}
return (
<div className="form-container">
{renderMessage()}
<form onSubmit={this.handleSubmit}>
<div className="field">
<label>First Name</label>
<input type="text" name="email" placeholder="First Name" ref="email" />
</div>
<div className="field">
<label>Password</label>
<input type="text" name="password" placeholder="Last Name" ref="password"/>
</div>
<button className="form-button" type="submit">{renderLoading()}</button>
</form>
</div>
);
}
}
export default connect(
(state) => {
return state;
}
)(Home);
Have you read the Redux integration guide located here? Odds are Redux is implementing shouldComponentUpdate and preventing your components from being rendered. Here's a trick you can use,
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {Redirect, withRouter} from 'react-router-dom'
class DashBoard extends Component {
constructor(props) {
super(props);
}
render() {
if (this.props.auth.token) {
return (
<h2>Here will be dashboard with items.</h2>
);
} else {
return <Redirect to={{pathname: '/'}} push/>
}
}
}
export default withRouter(connect(
(state) => {
return state;
}
)(DashBoard));
change your browser
make sure Your browser is accepting cookies

Resources