Redux: form input fields stay blank - javascript

I installed redux-form using this template, attached the reducer and checked that it is running fine in redux devtools.
I can see the actions flow is good while typing but the form values and the input are empty after each keystroke.
There are no errors in the console and I can't find any clues.
I'm missing something small, maybe it's a component rendering or maybe it's about the react version...
My packages:
"react": "15.3.2",
"redux-form": "^6.2.0",
My login form:
import React from 'react';
import { Field, reduxForm } from 'redux-form/immutable';
const renderField = ({ input, label, type, meta: { touched, error } }) => {
console.log(input);
return (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
};
class FormLogin extends React.Component { // eslint-disable-line react/prefer-stateless-function
static propTypes = {
handleSubmit: React.PropTypes.func
};
render() {
const { error, handleSubmit } = this.props;
return (
<div>
<input type="text" name="ah1" />
<form onSubmit={handleSubmit}>
<input type="text" name="ah2" />
<div>
<Field id="username" name="username" type="text" component={renderField} label="Username" />
</div>
<div>
<Field id="password" name="password" type="text" component={renderField} label="Password" />
</div>
{error && <strong>{error}</strong>}
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default reduxForm({
form: 'FormLogin'
})(FormLogin);

For me, I didn't name the reducer the exact name from the examples, which unfortunately lead to this difficult-to-debug error.
Make sure the reducer is listed as 'form: formReducer' as the example shows.

found the problem if anyone is getting here to find an answer.
there is a hack to fix it.
you can find more in here:
https://github.com/mxstbr/react-boilerplate/issues/958

Related

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

I'm trying to create a sign up form with an input for a users address. The address input uses the google autocomplete address api.
I'd like to be able to keep it as a Formik field, so I can use Yup validation on it.
The address input component looks like
// Google.jsx
import React from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
/* global google */
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.autocompleteInput = React.createRef();
this.autocomplete = null;
this.handlePlaceChanged = this.handlePlaceChanged.bind(this);
}
componentDidMount() {
this.autocomplete = new google.maps.places.Autocomplete(this.autocompleteInput.current,
{"types": ["address"]});
this.autocomplete.addListener('place_changed', this.handlePlaceChanged);
}
handlePlaceChanged(){
const place = this.autocomplete.getPlace();
console.log(place);
}
render() {
return (
<Field ref={this.autocompleteInput} id="autocomplete" type="text" name="address" placeholder="" />
);
}
}
export default SearchBar;
And my Form component looks like:
import React from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
import SearchBar from "./Google";
const LoginSchema = Yup.object().shape({
fName: Yup.string().required("Please enter your first name"),
address: Yup.string().required("invalid address"),
});
class Basic extends React.Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-lg-12">
<Formik
initialValues={{
fName: "",
postal: "",
}}
validationSchema={LoginSchema}
onSubmit={(values) => {
console.log(values);
console.log("form submitted");
}}
>
{({ touched, errors, isSubmitting, values }) =>
!isSubmitting ? (
<div>
<div className="row mb-5">
<div className="col-lg-12 text-center">
<h1 className="mt-5">LoKnow Form</h1>
</div>
</div>
<Form>
<div className="form-group">
<label htmlFor="fName">First Name</label>
<Field
type="text"
name="fName"
className={`mt-2 form-control
${touched.fName && errors.fName ? "is-invalid" : ""}`}
/>
<ErrorMessage
component="div"
name="fName"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<Field name="address" component={SearchBar} placeholder="" />
<ErrorMessage
component="div"
name="address"
className="invalid-feedback"
/>
</div>
<button
type="submit"
className="btn btn-primary btn-block mt-4"
>
Submit
</button>
</Form>
</div>
) : (
<div>
<h1 className="p-3 mt-5">Form Submitted</h1>
<div className="alert alert-success mt-3">
Thank for your connecting with us.
</div>
</div>
)
}
</Formik>
</div>
</div>
</div>
);
}
}
export default Basic;
This returns an error of "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?".
Which is coming from my address input component at: <Field ref={this.autocompleteInput} id="autocomplete" type="text" name="address" placeholder="" />
Everything else is working, I just need to get past this last hurdle and I'll be good from here.
I will begin looking into the docs, but I'm unfortunately in a rush to get this done so I figured I'd try my luck here!
Any help is greatly appreciated! Thank you!
The Field component does allow you to get access to the underlying element, but not via ref. You need to pass it to innerRef instead.
<Field innerRef={this.autocompleteInput} id="autocomplete" type="text" name="address" placeholder=""/>
See documentation of Field here: https://formik.org/docs/api/field#innerref

React setState hook keeps resetting and rendering the page twice

I have an react app Form component split into Login and Signup forms. It is supposed to render the Signup by default but switch to Login if login is button is clicked. When login button is clicked, the page switches to the Login form very briefly before switching back to the Signup form. I don't know what is causing this. I have tried placing const [page, setPage] = setState("signup") in the parent App and passing setPage as a prop along with page. This produced the same results. I believe this issue is similar to this one but that was not resolved.
Here is the app:
import Form from "./components/Signup-Form.js";
function App() {
return (
<div className="App">
<h1>Welcome</h1>
<Form />
</div>
);
}
export default App;
and Signup-Form.js:
import React from "react";
import { useState, useEffect } from "react";
import "./Forms.css";
import { InputField, Buttons } from "./Inputs";
function Form() {
const [page, setPage] = useState("signup");
const pageLabel = page;
let Signup = () => {
function toLogin() {
setPage("login");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company Name" id="comp-name" type="text" />
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Username" id="username" type="text" />
<InputField name="Email" id="email" type="email" />
<InputField name="Password" id="password" type="password" />
<InputField name="Confirm Password" id="confirm-password" type="password" />
</div>
<div className="btns">
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" />
<Buttons name="Log In" id="login-btn" type="button" cls="success" alt="true" onClick={toLogin} />
</div>
</form>
);
};
let Login = () => {
function toSignup() {
setPage("signup");
}
return (
<form action="" method="get" className="form">
<div className="input-container">
<InputField name="Company ID" id="comp-id" type="text" />
<InputField name="Password" id="password" type="password" />
</div>
<div className="btns">
<Buttons name="Log In" id="login-btn" type="submit" cls="success" />
<Buttons name="Sign Up" id="signup-btn" type="submit" cls="success" alt onClick={toSignup} />
</div>
</form>
);
};
let form = (formType) => (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{formType}
</div>
</div>
);
if (page === "signup") {
const signup = Signup();
return form(signup);
} else if (page === "login") {
const login = Login();
return form(login);
}
}
export default Form;
The reason why after you click on Login button and get Login page and the page immediately re-renders and you get the Signup page is conditional render in your example. Right after clicking on Login button your state still previous and for this reason after click you get the main (Signup) page.
Suggest to change the structure render into smth like this:
...
return (
<div className="outer-wrapper">
<div className="form-wrapper">
<label className="form-title">{pageLabel}</label>
{page === "signup" && Signup()}
{page === "login" && Login()}
</div>
</div>
);
Here is the example in an action - https://codesandbox.io/s/smoosh-water-6jj18?file=/src/App.js

React.js Bootsrap returning null error, when doing 'simple' tasks

So first time using bootstrap with React and I don't know what wrong here.
I am trying to change placeholder on input while on focus, with this code :
let ColorInput=document.getElementById('addRoomRoomColorInput');
console.log(ColorInput)
ColorInput.addEventListener('focus',()=>{
})
but I get an error code
""TypeError: Cannot read property 'addEventListener' of null""
I Cant even do console log on ColorInput variant.
my whole component :
import React from 'react'
import { Form,Button,Input } from 'react-bootstrap'
export default function Addroom() {
let ColorInput=document.getElementById('addRoomRoomColorInput');
console.log(ColorInput)
ColorInput.addEventListener('focus',()=>{
})
return (
<React.Fragment>
<div id='addRoomContainer'>
<h2 id='addRoomH2'>Room properties:</h2>
<Form.Control id='selectInputAddRoom' placeholder='Room type' as="select">
<option>Room type</option>
<option>Bedroom</option>
<option>Bathroom</option>
<option>Kitchen</option>
</Form.Control>
<Form.Control id='addRoomRoomNameInput' maxlength="10" type="text" placeholder="Room name" />
<Form.Text id='mutedTextRoomNameInput' className="text-muted">Maximum 10 charcters.</Form.Text>
<Form.Control id='addRoomRoomColorInput' type="text" placeholder="Room color" />
<Form.Text id='mutedTextRoomColorInput' className="text-muted">Red/Blue/Green/black.</Form.Text>
<Button id='addRoomProceedButton' variant="success">Proceed</Button>
</div>
</React.Fragment>
)
}
Thank you guys.
Here is simple example how bootstrap works with React. Basically it is more about React itself rather then bootstrap
You need to add handlers to Form.Control. I added onChange, onFocus, onBlur for example. It is simple functions in which you can change whatever you want. In this case if you need to change placeholder text you can use component state with useState.
import React, { useState } from "react";
import { Form, Button, Input } from "react-bootstrap";
export default function Addroom() {
const [state, setState] = useState("Room color");
const handleChange = () => {
console.log("handleChange");
};
const handleFocus = () => {
console.log("handleFocus");
setState("Room size");
};
const handleBlur = () => {
console.log("handleBlur");
setState("Room color");
};
return (
<React.Fragment>
<div id="addRoomContainer">
<h2 id="addRoomH2">Room properties:</h2>
<Form.Control
id="selectInputAddRoom"
placeholder="Room type"
as="select"
>
<option>Room type</option>
<option>Bedroom</option>
<option>Bathroom</option>
<option>Kitchen</option>
</Form.Control>
<Form.Control
id="addRoomRoomNameInput"
maxlength="10"
type="text"
placeholder="Room name"
/>
<Form.Text id="mutedTextRoomNameInput" className="text-muted">
Maximum 10 charcters.
</Form.Text>
<Form.Control
id="addRoomRoomColorInput"
type="text"
placeholder={state}
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<Form.Text id="mutedTextRoomColorInput" className="text-muted">
Red/Blue/Green/black.
</Form.Text>
<Button id="addRoomProceedButton" variant="success">
Proceed
</Button>
</div>
</React.Fragment>
);
}

How to create a dynamic input type component

I'm developing a dynamic component where the input can be used for several types: text, password, number, date, etc. The idea is to use this input, no matter the type and where to implement it, as long its adaptable. I thought using state was a nice idea, but I have no clue how to do this. Any thoughts?
import React, { Component } from 'react';
import './styles.css';
export default class InputField extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
password: false,
type: ''
}
}
render () {
return (
<div>
<label className='f-size'>{this.state.name}</label>
<input
className='input'
name={this.state.name}
placeholder={this.state.name}
value={this.props.value}
type={this.state.type}
onChange={this.props.onChange}
/>
<span className="errorMessage">{this.props.error}</span>
<span className="errorMessage">{this.props.missField}</span>
</div>
)
}
}
Thank you!
I personally think you should control this via props, seeing as the value will only be meaningful to the Input's parent.
I used this
const InputField = ({
name,
placeholder,
value,
type,
onChange,
error,
missField
}) => (
<div>
<label className="f-size">{name}</label>
<input
className="input"
name={name}
placeholder={placeholder}
value={value}
type={type}
onChange={onChange}
/>
<span className="errorMessage">{error}</span>
<span className="errorMessage">{missField}</span>
</div>
);
Parent component:
class App extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
state = {
value: '',
password: '',
};
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<div className="App">
<InputField
value={this.state.value}
type="number"
name="value"
onChange={this.handleChange}
/>
<InputField
value={this.state.password}
type="password"
name="password"
onChange={this.handleChange}
/>
</div>
);
}
}
Code Sandbox: https://codesandbox.io/s/y4ljv75k9
Edited to used a stateless component. Not sure if you want state to handle error messages but from your example, this is a valid solution.
<InputField type="text" />
<InputField type="password" />
<input
className='input'
name={this.state.name}
placeholder={this.state.name}
value={this.props.value}
type={this.props.type}
onChange={this.props.onChange}
/>
I would use props to change the type and manage the component.
You could then control the component from a form definition
You should use props not state, so you can pass
<InputType type="text" />
<InputType type="password" />
<InputType type="number" />
and for the other params you can use props also.
You could use this.props.type but the standard jsx input component is already dynamic as you can see from my example below :
var root = document.getElementById('root');
class InputField extends React.Component {
render() {
return (
<div>
<input type={this.props.type} />
</div>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<input type='date' />
<InputField type='password'/>
</div>
)
}
}
ReactDOM.render(<App />, root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
Is there a reason why you would like to use a custom input component?

How to go from one page to another

I have a SignIn form and I want to create the SignUp link.
On link click I want to open SignUp page.
I have created index.js nothing in that another app.js I wrote SignIn logic.
Here is the Code :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = event => {
event.preventDefault();
}
render(){
return (
<div class="container">
<form onSubmit={this.handleSubmit}>
<div id="login">
<div class="form-group">
<h2 align="center">Login Form</h2>
Email :
<input type="email" id="email" value={this.state.email} onChange={this.handleChange} class="form-control" placeholder="Email Address"/><br/>
Password :
<input type="password" id="password" value={this.state.password} onChange={this.handleChange} class="form-control" placeholder="Password"/><br/>
Sign Up<br/><br/>//here I want to change
<button id="send" disabled={!this.validateForm()} class="btn btn-default">Sign In</button>
</div>
</div>
</form>
</div>
);
}
}
export default App;
I have added the Anchor tag in that but it won't work . I want to create the link in place of anchor tag in that onclick the signup page will open. I have started to create signUp page also
here is my code:
import React, { Component } from 'react';
import './App.css';
export default class Signup extends Component {
render(){
return (
<div class ="container">
<form>
<div id="signup">
<div class="form-group">
First Name :
<input type="text" id="first" class="form-control" placeholder="First Name"/><br/>
Last Name :
<input type="text" id="last" class="form-control" placeholder="Last Name"/><br/>
Email :
<input type="email" id="email" class="form-control" placeholder="Email"/><br/>
Password :
<input type="password" id="password" class="form-control" placeholder="Password"/><br/>
Re-enter Password :
<input type="password" id="confirm" class="form-control" placeholder="Confirm Password"/><br/>
<button id="save">Save</button>
</div>
</div>
</form>
</div>
);
}
}
How do I create the routes to go from one page to another?
Use Link instead of a tag:
import { Link } from 'react-router-dom';
.
.
<Link to='/signup'>Sign Up</Link>
EDIT: I'm updating the code for your solution for now, but I need you to understand you might not be getting such a solution whenever you post questions here. Stack Overflow requires you to read through any documentation and do extensive research before asking any question.
I need you to look at the code below and fully understand it by reading the React Router docs before copy-pasting it.
Change your App.js to:
import React, { Component } from 'react';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import Signup from './Signup';
import './App.css';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
handleSubmit = event => {
event.preventDefault();
}
render() {
return (
<div class ="container">
<form onSubmit={this.handleSubmit}>
<div id="login">
<div class="form-group">
<h2 align="center">Login Form</h2>
Email :
<input type="email" id="email" value={this.state.email} onChange={this.handleChange} class="form-control" placeholder="Email Address"/><br/>
Password :
<input type="password" id="password" value={this.state.password} onChange={this.handleChange} class="form-control" placeholder="Password"/><br/>
<Link to="/signup">Signup</Link>
<button id="send" disabled={!this.validateForm()} class="btn btn-default">Sign In</button>
</div>
</div>
</form>
</div>
)
}
}
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path='/' component={Login}/>
<Route path='/signup' component={Signup}/>
</Switch>
</Router>
);
}
}
export default App;
and your expected working is achieved. Let me know if that solved by accepting this answer, or comment below.
P.S: React Router docs: https://reacttraining.com/react-router/web/guides/philosophy
Happy Coding!
If you are using react-router 4.x and above, then import it like this
import {Link} from 'react-router-dom'
For react-router versions < 4.x
import {Link} from 'react-router';
And in your return, you can link to another page by
<Link to="/signup">Signup</Link>

Categories