I am recently working on a react project which is creating taking the input from the redux-form#8.3.7. But the issue is it is not taking the value in the form.
On checking the redux-dev tool the value is replacing the previous one, I searched for a similar issue throughout the internet could not find a solution for it.
My Code
Reducers
import { combineReducers } from "redux";
import { reducer as formReducer } from 'redux-form'
import ocaFormFieldReducer from "./ocaFormReducers/ocaFormFieldReducer";
import stepperActiveStepReducer from "./ocaFormReducers/stepperActiveStepReducer";
import groupFieldReducer from "./ocaFormReducers/groupFieldReducer";
const reducer = combineReducers({
ocaFormFieldReducer,
stepperActiveStepReducer,
groupFieldReducer,
formReducer
});
export default reducer;
import React from "react";
import { connect } from "react-redux";
import { Field, reduxForm } from "redux-form";
import { withStyles } from "#material-ui/core/styles";
function ProductPlanning(props) {
const { classes, formFieldLoading, formFieldData, handleActiveStep, activeStep, cancelFormProgress, setGroupFieldApiStart, groupFieldData } = props;
return (
<div className={classes.root}>
{formFieldLoading && <LoadingScreen />}
<form>
<Field name="SUrya" component="input" type="text" />
</form>
)
}
export default reduxForm({ form: "ocaFormData" })(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ProductPlanning)));
It would be helpful if you can throw some light on this.
Thank you in advance.
The solution is simple and yet DUMB.
In Combine reducer, the value reducer should have a key-value pair with key name as form.
const reducer = combineReducers({
ocaFormFieldReducer,
stepperActiveStepReducer,
groupFieldReducer,
form: formReducer
});
Related
i am trying to include my common component in my main.js
this one I did it it successfully.
but in my common component, I am trying to print my redux data values.
so I created a method called handleClickForRedux to print the values.
I have included mapStateToProps and mapDispatchToProps
but still value is not printing at this line. console.log("event reddux props--->", props);
can you tell me how to fix it.
providing my code snippet and sandbox below.
https://codesandbox.io/s/react-redux-example-265sd
scroll.js
import React, { useEffect, useState, Fragment } from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
//import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import Typography from "#material-ui/core/Typography";
import Drawer from "#material-ui/core/Drawer";
import { bindActionCreators } from "redux";
import * as actionCreators from "../actions/actionCreators";
import { connect } from "react-redux";
import { compose } from "redux";
function SportsMouse(classes, props) {
// const [canEdit, setCanEdit] = useState(false);
function handleClickForRedux(event) {
console.log("event--->", event);
console.log("event reddux props--->", props);
}
return (
<Card>
<div onClick={handleClickForRedux}>I am here </div>
</Card>
);
}
SportsMouse.propTypes = {
classes: PropTypes.object.isRequired
};
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
)
)(SportsMouse);
main.js
import React from "react";
import { Link } from "react-router-dom";
import Scroll from "../commonComponents/scroll";
const Main = props => {
const { children, match, ...rest } = props;
return (
<div>
<h1>
<Scroll />
<Link to="/">Reduxstagram</Link>
</h1>
{React.Children.map(children, child => React.cloneElement(child, rest))}
</div>
);
};
export default Main;
Even when using material-ui, components only accept one argument. classes exists inside props. If you console.log(classes) you'll see that it contains all of your props, including material-ui's styles. It should be this:
function SportsMouse(props) {
I'm new to stackoverflow and quite new to using react/redux. I've been scanning over quite a few posts already to see if a similar post could provide me with an answer but I'm still left puzzled.
I currently have a presentational component "Repetitions" and a container component to get props from redux store and dispatch actions from the presentational component to redux store. I have the presentational component updating the redux store when I enter data into the input field but I am wanting to use the redux store to retrieve the input value so that when a user first comes on to the page the input value is "0" as that is the initial value inside the redux store.
I originally made a simple Counter component using react/redux and it was working ok. I have since made the "Repetition" component and altered the redux store to use a combinedreducer and this is when the problems seemed to start as neither components can read from the redux store.
Rootreducer.ts
import { combineReducers } from "redux";
import countReducer from "./example/reducer";
import repetitionsReducer from "./reps/reducer";
const rootReducer = combineReducers({
countReducer,
repetitionsReducer
})
export default rootReducer;
RepetitionsReducer.ts
import { RepetitionsState } from "../types";
import { AddRepetitionsAction } from "./actions";
export type RepetitionsActionType = AddRepetitionsAction;
export type Dispatch = (action: RepetitionsActionType) => void;
// The reducer updates the count
const initialState: RepetitionsState = {
repetitions: 0
};
const repetitionsReducer = (
state = initialState,
action: RepetitionsActionType
): RepetitionsState => {
switch (action.type) {
case "ADD_REPETITIONS":
return { ...state, repetitions: action.repetitions };
default:
return state;
}
}
export default repetitionsReducer;
RepetitionsContainer.ts
import { connect } from "react-redux";
import { RootState } from "../../store/types";
import { Dispatch } from "../../store/reps/reducer";
import { addRepetitions } from "../../store/reps/actions";
import Repetitions from "../../components/reps/Repetitions";
interface StateFromProps {
repetitions: number ;
}
interface DispatchFromProps {
updateRepetitions: (repetitions: number) => void;
}
export type RepetitionsProps = StateFromProps & DispatchFromProps;
const mapStateToProps = (state: RootState): StateFromProps => ({
repetitions: state.repetitions
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchFromProps => ({
updateRepetitions: (repetitions: number) => dispatch(addRepetitions(repetitions))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Repetitions);
RepetitionsComponent.ts
note: When I try to console.log "repetitions" I am getting undefined at the moment.
import React from "react";
import { RepetitionsProps } from "../../containers/reps/Repetitions";
const Repetitions: React.FunctionComponent<RepetitionsProps> = ({
repetitions,
updateRepetitions
}) => {
console.log(repetitions)
return (
<div>
<h3>Reps</h3>
<input
onChange={(event) => updateRepetitions(Number(event.target.value))}
value={ repetitions } // <-- This is the value i'm wanting to present to the user from the redux store
/>
</div>
);
};
export default Repetitions;
App.ts
import React from "react";
import ReactDOM from "react-dom";
import * as serviceWorker from "./serviceWorker";
import Header from "./components/header/Header";
import { Provider } from "react-redux";
import { createStore } from "redux";
import Counter from "./containers/example/Counter";
import Repetitions from "./containers/reps/Repetitions";
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from "./store/reducer";
const store = createStore(rootReducer, composeWithDevTools());
console.log(store.getState())
function App() {
return (
<div className="App">
<Header title={"Rep count"} />
<Repetitions />
<br />
<br />
<br />
<Counter />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
The expected results I would be hoping to see would be a "0" presented in the input box underneath the "Reps" header when a user first loads the page. Instead the box is empty but the redux store shows the value for repetitions as "0".
reps-input-desired-results
It is also worth noting that the counter below the input field used to read "0" from the redux store when I first loaded the page however now it is also undefined.
Thank you for taking the time to look at my post. Any help would be greatly appreciated!
Hmmm... something is wrong here:
First of all, your state for repetition is currently holding an object. It should hold a simple number.
Secondly, the name of the repetition state on the store (from the snapshot you've attached) is "repetitionReducer" and not "repetition" as you try to fetch it in mapStateToProps:
const mapStateToProps = (state: RootState): StateFromProps => ({
repetitions: state.repetitions // <- this one here...
});
Hope this helps :)
The closest to doing this is reduxForm().getFormState() of which it's not well documented
You'll want to use the formValueSelector that is exported from redux-form. While you can dive directly into the state tree and pull things out for yourself, using the selector exported by redux-form means that you aren't taking a dependency on any implementation details of redux-form.
You use it like:
import React from 'react';
import { formValueSelector } from 'redux-form';
class App extends React.Component {
// ...
}
const formName = 'myForm'; // Name of form you want
const myFormValueSelector = formValueSelector(formName);
const mapStateToProps = state => ({
name: myFormValueSelector(state, 'name') // selects the name field value
});
export default connect(mapStateToProps)(App);
You can find documentation for this method here
Form values will be available on the redux store. You can get it from any app components.
Mini example,
index.js,
import React from 'react';
import ReactDOM from 'react-dom';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import App from './src/components';
const rootReducer = combineReducers({
form: formReducer,
});
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(reducers);
ReactDOM.render(
<Provider store={store}>
<App />
<Provider>
, document.querySelector('.root'));
app.js,
import React, { Component } from 'react';
import { change, Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
class App extends Component {
...
render() {
console.log(this.props.forms); // This fill print information about all of your app forms
return <div />;
}
}
function mapStateToProps(state) {
return {
forms: state.form;
}
}
export default reduxForm({
form: 'someForm',
})(connect(
mapStateToProps,
null
)(App));
In app.js, console.log will print form data like this,
{
someForm: {...someForm props},
someOtherForm: {...someOtherForm props},
}
Currently, I'm working on a small application that utilizes modals. I don't want to use 'ready-to-use' packages like react-modal and instead decided to try to do it on my own.
1) A reducer in src/reducers/modalReducer.js
const modalReducer = (state = {
show: true,
}, action) => {
switch (action.type) {
case 'TOGGLE_MODAL':
console.log('reducer worked out')
state = {...state, show: !state.show }
break
default:
return state
}
}
export default modalReducer
My reducers/index.js
import { combineReducers } from 'redux'
import modalReducer from './modalReducer'
const reducers = combineReducers({
modal: modalReducer
})
export default reducers
2) A store in src/store.js
import { createStore } from 'redux'
import reducer from './reducers/index'
export default createStore(reducer)
3) A Modal component in src/components/Modal.js. I want this component to be reusable and contain input forms which I'll add later.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { toggleModal } from '../actions/index'
import { bindActionCreators } from 'redux'
import '../css/Modal.css'
class Modal extends Component {
render () {
if(!this.props.show) {
return (<h1>FUC YOU</h1>)
}
console.log('HELLLO' + this.props.show)
return (
<div className='backdrop'>
<div className='my-modal'>
<div className='footer'>
<button className='close-btn' onClick={ () => toggleModal }>
X
</button>
</div>
<h1>{ this.props.title }</h1>
<hr/>
<div>
{ this.props.contents }
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return { show: state.modal.show }
}
const mapDispatchToProps = (dispatch) => {
return {
toggleModal: () => dispatch(toggleModal())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
My problem is that when I'm pressing the button x, in my modal nothing happens. It means that I did something wrong when was dispatching actions, but I have no idea what I missed...
At this point I just want my empty modal to be closed when the x button is pressed.
In my index.js I have the following structure:
import React from 'react'
import ReactDOM from 'react-dom'
import registerServiceWorker from './registerServiceWorker'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store.js'
import App from './components/App'
ReactDOM.render(
<Provider store = {store} >
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'))
registerServiceWorker()
My Modal component is within App
You're not actually calling the toggleModal() action creator. In addition, you're referencing the imported function, not the function you're getting as props:
onClick={ () => toggleModal }
The immediate fix would be: onClick={ () => this.props.toggleModal() }.
Having said that, there's two other ways you can improve this code.
First, you can pass toggleModal directly as the handler for onClick, like:
onClick={this.props.toggleModal}
Second, you can replace the mapDispatch function by using the "object shorthand" syntax supported by connect:
import {toggleModal} from "../actions";
const actions = {toggleModal};
export default connect(mapState, actions)(Modal);
Beyond that, I'd encourage you to read my post Practical Redux, Part 10: Managing Modals and Context Menus, which specifically shows how to implement modal dialogs using React and Redux, and points to additional resources on the topic.
Trying out React + Redux, and probably am doing something obviously stupid, because a component that fires an action to fetch data over the network does not get updated (re-rendered) when the data is fetched.
Here are the relevant bits of my code:
The top-level index.js serving as an entry point for the app:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reduxPromise from 'redux-promise';
import createLogger from 'redux-logger';
const logger = createLogger();
import routes from './routes';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(reduxPromise, logger)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory} routes={routes} />
</Provider>
, document.querySelector('.container'));
Top-level container App:
import React, {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions';
import Header from '../components/header';
import Showcase from '../components/showcase';
function mapStateToProps(state) {
return {
resources: state.resources
}
}
function mapDispatchToProps(dispatch) {
return {
fetchResources: () => {
dispatch(Actions.fetchResources());
}
}
}
class App extends Component {
render() {
console.log('props in App', this.props);
return (
<div>
<Header/>
<Showcase
fetchResources={this.props.fetchResources}
resources={this.props.resources}
/>
</div>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
Component that triggers an action to sends a request for data when it is about to mount and is supposed to show the fetched data:
import React, {Component} from 'react';
import {connect} from 'react-redux';
class Showcase extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.fetchResources();
}
render() {
console.log('resources', this.props);
return (
<div>
This is showcase
</div>
);
}
}
export default connect(state => ({resources: state.resources}))(Showcase)
Action Creator:
import * as types from '../constants/ActionTypes';
import axios from 'axios';
export function fetchResources() {
return {
type: types.FETCH_FIRST,
payload: axios.get('/sampledata/1.json')
}
}
Reducer for the fetch action:
import * as types from '../constants/ActionTypes';
export default function resourcesReducer (state={}, action) {
switch (action.type) {
case types.FETCH_FIRST:
console.log('about to return', Object.assign (state, {resources: action.payload.data }))
return Object.assign (state, {resources: action.payload.data });
default:
return state
}
};
and finally the root reducer:
import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';
const rootReducer = combineReducers({
navigationReducer,
resourcesReducer
});
export default rootReducer;
So, here is what I am observing. The action to request data is successfully triggered, a request is sent, the reducer receives it when the promise is resolved, and updates the state with the fetched data. At this point, I would expect the top-level App component and the Showcase component to detect that the store has updated, and to re-render, but I do not see it in the console.
Also, I am confused by redux-logger’s console output:
Specifically, I am surprized to see that the state contains reducers from the rootReducer — I don't know if it's right (an example on Redux logger Github page shows a state without reducers). It also seems surprising that the prev state as reported by redux-logger contains the same resourcesReducer object as the next state, although intuitively I would expect prev state to be more or less empty.
Could you please point out what I am doing wrong and how to get React components respond to the state changes?
==================================================
UPDATED:
1) Changed the mapStateToProps function in the App component so that it correctly maps to reducer states:
function mapStateToProps(state) {
return {
resources: state.resourcesReducer
}
}
2) Still passing the resources down to the `Showcase component:
render() {
console.log('props in App', this.props);
return (
<div>
<Header navigateActions={this.props.navigateActions}/>
React simple starter
<Showcase
fetchResources={this.props.fetchResources}
resources={this.props.resources}
/>
</div>
);
3) Trying to display resources on the screen by stringifying it to see what’s actually inside this object:
render() {
console.log('resources', this.props);
return (
<div>
This is showcase {JSON.stringify(this.props.resources)}
</div>
);
}
See this on the screen: This is showcase {}. The component does not seem to re-render.
Here’s the screenshot of the console showing that App’s props have updated with the values from the next state. Still, that did not cause the component to re-render:
UPDATED AGAIN: And my javascript-fu was poor, too. I did not quite realize that by returning Object.assign (state, {resources: action.payload.data }); I was in fact mutating the state, and that a simple inversion of arguments would let me achieve what I intended. Thanks to this discussion on SO for enlightenment.
I am surprized to see that the state contains reducers from the rootReducer
This is how it works. Take a closer look at combineReducers().
const rootReducer = combineReducers({
navigationReducer,
resourcesReducer
});
Recognise that it's not a list of parameters; it's a single object parameter. Perhaps it is clearer in verbose syntax:
var rootReducer = combineReducers({
navigationReducer: navigationReducer,
resourcesReducer: resourcesReducer
});
The resourcesReducer key points to the state returned by the resourcesReducer() function. That is, the state variable within the resourcesReducer() is just one part of the entire state.
The functions passed to connect() take the entire state as an argument. What yours should actually look like is this:
export default connect(state => ({
resources: state.resourcesReducer.resources
}))(Showcase);