I'm utilizing Redux form and the Redux Material UI package. Normally when I run code like this, it works, but for some reason, it's not able to get the value of the TextField. Does anyone know what's going on here?
My console.log statement just comes back with {special_instructions: undefined}
import React from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form/immutable';
/**
* Components
*/
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
export class EditRequestForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
cancel() {
this.props.handleCancelEdit();
}
onSubmit(formProps) {
const request = {
special_instructions: formProps.get('special_instructions'),
};
console.log('request', request);
}
render() {
// console.log(this.props.request);
const { handleSubmit, pristine, reset, submitting, errors } = this.props
let request = this.props.request;
return (
<form className="page-form__wrapper page-body__wrapper read-request-page">
<TextField
name="area_instructions"
multiLine={true}
fullWidth={true}
id="area_instructions"
defaultValue={request.area_instructions}
/>
<div className="page-form__block draft-field bg-grey">
<RaisedButton
primary={true}
onTouchTap={handleSubmit(this.onSubmit)}
label="Update"
/>
<RaisedButton
secondary={true}
onTouchTap={handleSubmit(::this.cancel)}
label="Cancel"
/>
</div>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return {
dispatch,
};
}
export default reduxForm({
form: 'editRequest',
})(connect(mapDispatchToProps)(EditRequestForm));
Related
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 */
})
}
}
/* ... */
In my file called app.jsx i have one import from the component "atividades":
import React from 'react'
import { Container } from 'semantic-ui-react'
import atividades from '../atividades/atividades'
export default props => (
<Container>
<h1>Teste</h1>
<atividades />
</Container>
)
But only the h1 is rendering...
This is my atividades component:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { Form } from 'semantic-ui-react'
import { addWorkout, searchWorkout } from './workOutActions'
import { Button, Icon } from 'semantic-ui-react'
const workoutOptions = [
{ text: 'correr', value: 'run' },
{ text: 'nadar', value: 'swimming' },
{ text: 'andar de bicicleta', value: 'bike' },
]
class atividades extends Component {
constructor(props){
super(props)
}
componentWillMount(){
this.props.searchWorkout()
}
render() {
const { addWorkout, searchWorkout, tempoGasto, tipoTarefa, data} = this.props
return (
<div role='form'>
<h6>Inserir atividade</h6>
<Form>
<Form.Group widths='equal'>
<Form.Input fluid placeholder='Tempo gasto' />
<Form.Select
fluid
label='Atividade'
options={workoutOptions}
/>
<Button animated='vertical'>
<Button.Content hidden>Shop</Button.Content>
<Button.Content visible>
<Icon name='shop' />
</Button.Content>
</Button>
</Form.Group>
</Form>
</div>
)
}
}
const mapStateToProps = state => ({tempoGasto: state.workout.tempoGasto, tipoTarefa: state.workout.tipoTarefa, data: state.workout.data})
const mapDispatchToProps = dispatch =>
bindActionCreators({ addWorkout, searchWorkout }, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(atividades)
It's not showing nothing in the console, but the element workout is not rendering, the visual studio code says that the import is not being used.
The first letter of React components must be capitalized or it thinks it’s a built in component like div or p or span.
This link has more info:
ReactJS component names must begin with capital letters?
I'm trying to insert a personalized theme into my component, however when using console.log() in properties in styles I get a return that the object is empty.
I do not get any kind of error warning, why is this happening?
// LIBRARY AND MODULES
import React from "react";
// STYLES
import GlobalStyle from "../../styles/global";
import { ContainerPage, FooterContainerPage, FormElement } from "./styles";
// COMPONENTS
import CardRepository from "../../components/stateless/specifics/Cards/Repository/Repository";
import Input from "../../components/stateless/generics/Input/Input";
import Button from "../../components/stateless/generics/Button/Button";
const themes = {
buttons: {
searchRepository: {
bgColor: "#73c894",
txtColor: "#ffffff",
hoverBgColor: "#218838"
}
}
};
export default class App extends React.Component {
state = {
buttonIsDisabled: false
};
searchRepository() {
alert("ae");
}
render() {
const { buttonIsDisabled } = this.state;
return (
<React.Fragment>
<GlobalStyle />
<FooterContainerPage>
<FormElement>
<Button
theme={themes.buttons.searchRepository}
type="button"
onClick={this.searchRepository}
disabled={buttonIsDisabled}
required={true}
>
BUSCAR
</Button>
</FormElement>
</FooterContainerPage>
</React.Fragment>
);
}
}
I'm not able to type values in input fields using redux-form. I have the following reducer
import {combineReducers} from 'redux';
import session from './sessionReducer';
import profile from './profileReducer';
import map from './mapReducer';
import { reducer as formReducer } from 'redux-form'
const rootReducer = combineReducers({
// short hand property names
session,
profile,
map,
form: formReducer
})
export default rootReducer;
and here is the store
import { createStore, combineReducers, applyMiddleware } from 'redux'
import createLogger from 'redux-logger'
import thunk from 'redux-thunk'
import { routerReducer, routerMiddleware, push } from 'react-router-redux'
import reducers from '../reducers'
import { browserHistory } from 'react-router';
const middleware = [ thunk ];
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger());
}
middleware.push(routerMiddleware(browserHistory));
// Add the reducer to your store on the `routing` key
const store = createStore(
combineReducers({
reducers,
routing: routerReducer
}),
applyMiddleware(...middleware),
)
export default store;
component
import React, {PropTypes, Component} from 'react';
import Upload from './Upload';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as profileActions from '../../../actions/profileActions';
import EventsCalendar from '../../common/EventsCalendar';
import { Field, reduxForm } from 'redux-form'
import ProfileForm from './ProfileForm';
import {
Form,
FormGroup,
FormControl,
ControlLabel,
Tabs,
Tab,
InputGroup,
Label,
HelpBlock,
Grid,
Row,
Button,
Col
} from 'react-bootstrap';
class Profile extends Component {
static propTypes = {
profile: PropTypes.object.isRequired,
};
constructor(props) {
super(props);
this.state = {
profile: {
username: '',
password: '',
email: ''
}
}
//this.onUpdate = this.onUpdate.bind(this)
}
handleSubmit = (values) => {
// Do something with the form values
console.log(values);
}
componentDidMount() {
this.props.actions.getProfile()
}
componentWillReceiveProps(nextProps) {
if (nextProps.profile !== this.props.profile) {
}
}
render() {
console.log(this.props.profile);
const {profile} = this.props.profile;
const { handleSubmit } = this.props;
return (
<div className="row">
<Col lg={10}>
<Tabs defaultActiveKey={1} id="uncontrolled-tab-example">
<Tab eventKey={1} title="Vendor Data">
<ProfileForm onSubmit={this.handleSubmit} data = {this.props.profile}/>
</Tab>
<Tab eventKey={3} title="Events Calendar">
<EventsCalendar/>
</Tab>
</Tabs>
</Col>
<Col lg={2}>
<Upload/>
</Col>
</div>
);
}
}
function mapStateToProps(state) {
return {
profile: state.default.profile,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(profileActions, dispatch)
};
}
Profile = reduxForm({
form: 'profileForm' // a unique name for this form
})(Profile);
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
when I'm typing I see in console that the state is changing
the attached form component
import React, {Component} from 'react';
import {Field, reduxForm} from 'redux-form';
import FieldFormControl from '../../common/FieldFormControl';
import {
FormGroup,
FormControl,
ControlLabel,
Button
} from 'react-bootstrap';
class ProfileForm extends Component {
render() {
const {handleSubmit, profile, pristine, reset, submitting} = this.props;
return (
<form onSubmit={handleSubmit}>
<FormGroup controlId="signup-name">
<Field type="text" name="firsname" placeholder="test" value component={FieldFormControl}>Vorname</Field>
</FormGroup>
<FormGroup controlId="signup-username">
<Field type="text" name="lastname" placeholder={profile.username} value={profile.username} component={FieldFormControl}>Name</Field>
</FormGroup>
<FormGroup controlId="signup-email">
<Field type="text" name="email" placeholder={profile.username} value={profile.username} component={FieldFormControl}>Vorname</Field>
</FormGroup>
<Button
bsStyle="primary"
type="submit"
//disabled={pristine || submitting}
block
>Speichern</Button>
</form>
);
}
}
// Decorate the form component
ProfileForm = reduxForm({
form: 'profileForm' // a unique name for this form
})(ProfileForm);
export default ProfileForm;
the bootstrap override to be compatible with redux-form
import React, { Component } from 'react';
import {FormGroup, FormControl, ControlLabel} from 'react-bootstrap';
export default class FieldFormControl extends Component {
render () {
const { placeholder, type, input, meta} = this.props;
return (
<FormGroup controlId={input.name} validationState={meta.error ? 'error' : 'success'}>
<ControlLabel>{this.props.children}</ControlLabel>
<FormControl type={type} placeholder={placeholder} value={input.value} onChange={input.onChange} />
<FormControl.Feedback />
</FormGroup>
);
}
}
Remove the value prop from your Field components, redux-form handles updating the value and passing it to the component that you pass it. I'm assuming the idea here is to provide initial value, but this is not the place to do that.
<Field type="text" name="email" placeholder={profile.username} component={FieldFormControl}>Vorname</Field>
You can also pass all the input props to your FormControl in your FieldFormControl so you get onFocus, onBlur, etc., all provided by redux-form.
<FormControl placeholder={placeholder} {...input} />
If you want to initialize the fields with values, either use initialValues when you connect using reduxForm, or initialize if it needs to happen after the form mounts.
And finally, you're using combineReducers twice in such a way that most of your reducers are nested in a way that you didn't intend. To simplify this, I would import the routerReducer in your reducers/index.js file, and add it to your combineReducers there.
const rootReducer = combineReducers({
// short hand property names
session,
profile,
map,
form: formReducer,
routing: routerReducer,
});
Then, in your store, you'll just have
const store = createStore(
reducers,
applyMiddleware(...middleware),
);
You should then see that you'll have all your keys in your state (session, profile, form, routing, etc.) instead of just default and routing.
I do not think it is the redux-form's issue.
Instead, I think your application listens onChange of your input, and dispatch action to redux. So this is the root cause: you dispatch onChange action, causing the redux state to update, (I think your code has not change it in reducer) and after that, redux flushes the render UI.
To fix it, you:
typically, when you dispatch the onChange action, in your reducer, update yuor redux state explicitly. then new state will flush your UI automatically.
e.g. your reducer should have similar like this:
function myReducer(state = initialState, action) {
switch (action.type) {
case MY_INPUT_VALUE_CHANGE:
return Object.assign({}, state, {
vornname: action.data
})
default:
return state
}
}
i don't know what im doing wrong.
I thought i got the point how to implement with redux.
My Problem is that the state of the Component is not propagating to the Component after the state changed. I know we have to create new state object and i'm sure im doing it right. But there is no changes.
And the other question is, why the state is in the object "resetLink" see image. Why is it not stored in the state Object?
Please help me to get it work.
Action for the redux:
export const sendResetLink = (email) => {
return {
type: RESET_LINK,
email
}
}
class App extends React.Component {
render() {
return <VisibleResetLink/>
}
}
This is where the magic with props and dispatch function happens:
import {connect} from 'react-redux';
import SendResetLink from '../components/SendResetLink.jsx';
import {sendResetLink} from '../actions/index'
import _ from 'lodash';
const mapDispatchToProps = (dispatch) => {
return {
onClick: (email) => {
dispatch(sendResetLink(email))
}
}
}
const mapStateToProps = (state) => {
console.log("actual state", state);
return _.assign({} , {state: state.resetLink});
}
const VisibleResetLink = connect(
mapStateToProps,
mapDispatchToProps
)(SendResetLink)
export default VisibleResetLink
This is the Component which load props but never rerender them when they change.
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
class SendResetLink extends React.Component {
constructor(props, email, result) {
super(props);
console.log('props',props);
this.onClick = props.onClick;
this.result = props.state.result;
this.input = props.state.email;
}
renderResult (result){
console.log("renderResult",result);
if(result)
return <div className="card-panel deep-orange lighten-4">Invalid username and password.</div>
}
render() {
return <div>
{this.renderResult(this.result)}
{this.result}
<form className="col s12" action="/login" method="post" onSubmit={e => {
e.preventDefault()
if (!this.input.value.trim()) {
return
}
this.onClick(this.input.value);
this.input.value = ''
} }>
<div className="row">
<div className="input-field col s12">
<i className="material-icons prefix">email</i>
<input id="email" type="email" name="email" className="validate" ref = {(node) => this.input = node } />
<label for="email">Email</label>
</div>
</div>
<div className="divider"></div>
<div className="row">
<div className="col m12">
<p className="right-align">
<button className="btn btn-large waves-effect waves-light" type="submit" name="action">Send reset key</button>
</p>
</div>
</div>
</form></div>
}
}
SendResetLink.propTypes = {
onClick: PropTypes.func.isRequired,
state: PropTypes.object.isRequired
}
export default SendResetLink
And this is the other relevant code snippet, where the reducer is implemented.
import _ from 'lodash';
const resetLink = (state = {email:"test#test.de", result:true}, action) => {
console.log('state', state)
switch (action.type) {
case 'RESET_LINK':
return _.assign({},state,{email: action.email, result: false});
default:
return state
}
}
export default resetLink;
import { combineReducers } from 'redux'
import resetLink from './ResetLinkReducer.jsx'
const resetApp = combineReducers({
resetLink
})
export default resetApp
import App from './components/app.jsx';
import {Provider} from 'react-redux';
import { createStore } from 'redux';
import { render } from 'react-dom';
import React from 'react';
import resetApp from './reducers/index.js';
let store = createStore(resetApp,{});
console.log(store)
render(<Provider store={store}>
<App />
</Provider>, document.getElementById('sendResetLinkComponent'));
console logs. After click the renderResult should change to false. But it stays on true
You set this.result in your SendResetLink component only once in the constructor, which is only executed when the component is instantiated. The constructor will not be executed every time the application's state changes:
this.result = props.state.result;
Instead of assigning this part of the state to an instance attribute of your react component, simply use the props attribute directly in your render() function:
{this.renderResult(this.props.state.result)}