There is a Login component
// #flow
import type {
TState as TAuth,
} from '../redux';
import * as React from 'react';
import Button from '#material-ui/core/Button';
import FormControl from '#material-ui/core/FormControl';
import Input from '#material-ui/core/Input';
import InputLabel from '#material-ui/core/InputLabel';
import Paper from '#material-ui/core/Paper';
import { withNamespaces } from 'react-i18next';
import { Link } from 'react-router-dom';
import {
connect,
} from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import useStyles from './styles';
import { login } from '../../redux';
import { push } from 'connected-react-router';
const logo = './assets/images/logo.png';
const {
useEffect,
} = React;
type TInputProps = {
input: Object,
meta: {
submitting: boolean,
}
}
const UserNameInput = (props: TInputProps) => (
<Input
id="userName"
name="userName"
autoComplete="userName"
autoFocus
{...props}
{...props.input}
disabled={props.meta.submitting}
/>
);
const PasswordInput = (props: TInputProps) => (
<Input
name="password"
type="password"
id="password"
autoComplete="current-password"
{...props}
{...props.input}
disabled={props.meta.submitting}
/>
);
type TProps = {
t: Function,
login: Function,
handleSubmit: Function,
error: string,
submitting: boolean,
auth: TAuth,
}
// TODO: fix flow error inside
const Login = ({
t,
login,
handleSubmit,
error,
submitting,
auth,
}: TProps) => {
const classes = useStyles();
useEffect(() => {
if (auth) {
console.log('push', push);
push('/dashboard');
}
}, [auth]);
return (
<main className={classes.main}>
<Paper className={classes.paper}>
<img src={logo} alt="logo" className={classes.logo} />
<form
className={classes.form}
onSubmit={handleSubmit((values) => {
// return here is very important
// login returns a promise
// so redux-form knows if it is in submission or finished
// also important to return because
// when throwing submissionErrors
// redux-form can handle it correctly
return login(values);
})}
>
<FormControl margin="normal" required fullWidth>
<Field
name="userName"
type="text"
component={UserNameInput}
label={
<InputLabel htmlFor="userName">{t('Username')}</InputLabel>
}
/>
</FormControl>
<FormControl margin="normal" required fullWidth>
<Field
name="password"
type="password"
component={PasswordInput}
label={
<InputLabel htmlFor="password">{t('Password')}</InputLabel>
}
/>
</FormControl>
<div className={classes.error}>{error}</div>
<Button
disabled={submitting}
type="submit"
fullWidth
variant="outlined"
color="primary"
className={classes.submit}
>
{t('Sign in')}
</Button>
<Link className={classes.forgot} to="/forgot">
{t('Forgot Password?')}
</Link>
</form>
</Paper>
</main>
);
};
const mapStateToProps = ({ auth }) => ({ auth });
const mapDispatchToProps = {
login,
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(
reduxForm({ form: 'login' })(withNamespaces()(Login))
);
In the useEffect hook the push from connected-react-router is used. The hook fires ok but nothing happens after it.
The same way, push is used in login action.
// #flow
import type {
TReducer,
THandlers,
TAction,
TThunkAction,
} from 'shared/utils/reduxHelpers';
import type {
TUser,
} from 'shared/models/User';
import createReducer from 'shared/utils/reduxHelpers';
import urls from 'constants/urls';
import axios, { type $AxiosXHR } from 'axios';
import { SubmissionError } from 'redux-form';
import { push } from 'connected-react-router';
export type TState = ?{
token: string,
result: $ReadOnly<TUser>,
};
export const ON_LOGIN = 'ON_LOGIN';
export const login: ({ userName: string, password: string }) => TThunkAction =
({ userName, password }) => async (dispatch, getState) => {
const res: $AxiosXHR<{username: string, password: string}, TState> =
await axios.post(`${urls.url}/signin`, { username: userName, password })
.catch((err) => {
throw new SubmissionError({ _error: err.response.data.message });
});
const data: TState = res.data;
dispatch({
type: ON_LOGIN,
payload: data,
});
push('/dashboard');
};
const handlers: THandlers<TState, TAction<TState>> = {
[ON_LOGIN]: (state, action) => action.payload,
};
const initialState = null;
const reducer: TReducer<TState> = createReducer(initialState, handlers);
export default reducer;
Here everything goes successful and dispatch happens and there is no push happening again.
Whats the problem?
Shouldn't there be dispatch(push('/dashboard')); ?
You just have to make sure that you do not create your middleware and pass in the history api before calling createRootReducer function.
If you try to create your middleware with routerMiddleware(history) too early , history will be passed in as undefined. Follow the README.md as it explains the exact execution order.
// configureStore.js
...
import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'
...
export const history = createBrowserHistory()
export default function configureStore(preloadedState) {
const store = createStore(
createRootReducer(history), // <-- Initiates the History API
preloadedState,
compose(
applyMiddleware(
routerMiddleware(history), // <--- Now history can be passed to middleware
// ... other middlewares ...
),
),
)
return store
}
Related
Trying to store user input from form into redux, however value accessed through useSelector is always undefined.
Slice component:
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "userSettings",
initialState: {
interval: 15000,
},
reducers: {
updateInterval: (state, action) => {
state.interval = action.payload
}
},
});
export const { updateInterval } = userSlice.actions;
export const userRefreshInterval = (state) => state.userSettings;
export default userSlice.reducer;
Input form component:
import React, { useState } from 'react';
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import { useSelector, useDispatch } from 'react-redux'
import {userRefreshInterval, updateInterval} from "./store/userSlice.js";
export default function UserSettingsForm() {
const [refreshInterval, setInterval] = useState("");
const dispatch = useDispatch();
const interval = useSelector(userRefreshInterval);
console.log(interval); // <--- always undefined
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateInterval(refreshInterval));
};
const handleChangeInterval = (text) => {
setInterval(text);
};
return (
<Form onSubmit={handleSubmit} style={{margin: 10}} inline>
<FormGroup className="mb-2 mr-sm-2 mb-sm-0">
<Label for="refreshInterval" className="mr-sm-2">Refresh Interval:</Label>
<Input type="text" name="refreshInterval" id="refreshInterval" placeholder="interval" onChange={(e) => handleChangeInterval(e.target.value)} />
</FormGroup>
<FormGroup className="mb-2 mr-sm-2 mb-sm-0">
<Label for="roundDecimal" className="mr-sm-2">Round results to decimal:
</Label>
<Input type="text" name="roundDecimal" id="roundDecimal" placeholder="roundDecimal" />
</FormGroup>
<Button>Submit</Button>
</Form>
);
}
Update with store.js as asked:
import { configureStore } from '#reduxjs/toolkit'
import userReducer from "./userSlice";
export default configureStore({
reducer: {
user: userReducer
}
})
Feeling like missing something simple, pls help to identify the cause of the issue.
I haven't seen your store first.
try this
export const userRefreshInterval = (state) => state.user;
Because you have named your slicer as user. If you want to get state using
export const userRefreshInterval = (state) => state.userSettings;
Configure your store like the bellow
export default configureStore({
reducer: {
userSettings: userReducer
}
})
// your component
import React, { useState } from "react";
import { Button, Form, FormGroup, Label, Input } from "reactstrap";
import { useSelector, useDispatch } from "react-redux";
import { updateInterval } from "./store/userSlice.js";
export default function UserSettingsForm() {
const [refreshInterval, setInterval] = useState("");
const dispatch = useDispatch();
// need to change here, no need of userRefreshInterval, no need to even export or create this function in reducer file
const interval = useSelector((state) => state.user.interval);
console.log(interval); // <--- always undefined
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateInterval(refreshInterval));
};
const handleChangeInterval = (text) => {
setInterval(text);
};
return (
<Form onSubmit={handleSubmit} style={{ margin: 10 }} inline>
<FormGroup className="mb-2 mr-sm-2 mb-sm-0">
<Label for="refreshInterval" className="mr-sm-2">
Refresh Interval:
</Label>
<Input
type="text"
name="refreshInterval"
id="refreshInterval"
placeholder="interval"
onChange={(e) => handleChangeInterval(e.target.value)}
/>
</FormGroup>
<FormGroup className="mb-2 mr-sm-2 mb-sm-0">
<Label for="roundDecimal" className="mr-sm-2">
Round results to decimal:
</Label>
<Input
type="text"
name="roundDecimal"
id="roundDecimal"
placeholder="roundDecimal"
/>
</FormGroup>
<Button>Submit</Button>
</Form>
);
}
// your reducer file
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "userSettings",
initialState: {
interval: 15000,
},
reducers: {
updateInterval: (state, action) => {
state.interval = action.payload;
},
},
});
export const { updateInterval } = userSlice.actions;
// removed userRefreshInterval function
export default userSlice.reducer;
Let me know if it works!
i am working on Select feature, where i need to select a value from the select field. i am using redux-form, and working with react-select and integrating with redux-form. when i select a option from the list of option, handleSubmit function is not being triggred. below is the code snippet of react-form -Field implementation
import React from "react";
import { Field, reduxForm } from "redux-form";
import ReduxFormSelect from "./ReduxFormSelect";
const SelectInputField = (props) => {
const { userOptions, handleSubmit, name } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name={name}
component={ReduxFormSelect}
sytle={styles.selectInput}
options={userOptions}
/>
</form>
);
};
export default reduxForm({
form: "wizard",
initialValues: {
FilterFor: {
label: "correct",
value: "correct",
},
},
})(SelectInputField);
below is the code where i am using Select component from react-select integrating the input field
generated by redux-form -- ReduxFormSelect component
import React from "react";
import Select from "react-select";
const ReduxFormSelect = (props) => {
const { input, options } = props;
return (
<Select
{...input}
onChange={(value) => {
input.onChange(value);
}}
onBlur={() => input.onBlur(input.value)}
options={options}
/>
);
};
export default ReduxFormSelect;
below is where the handleSubmit function is sent as props to SelectInputComponent, where this handleSubmit function is not being triggered, when one of the options being changed
import React, { Fragment } from "react";
import { Container, Row, Col } from "react-bootstrap";
import { connect } from "react-redux";
import { reduxForm } from "redux-form";
import { filteredResultsAction } from "../../Actions";
import SelectInputField from "../reusableComponents/SelectInputField";
import ShowFilteredResults from "./ShowFilteredResults";
const ShowAttemptedQue = (props) => {
const { ans, opt_values } = props;
const handleSubmit = (values) => {
console.log("changed option values",values);
};
return (
<Fragment>
<Container>
<Row>
<Col>Attempted Questions:</Col>
<Col md="auto">
Filted By :{" "}
<SelectInputField
name="filterFor"
userOptions={opt_values}
handleSubmit={handleSubmit}
/>
</Col>
</Row>
<ShowFilteredResults result_data={ans} />
</Container>
</Fragment>
);
};
const mapStateToProps = (state) => {
return {
ans: state.updatedTempVal.attempted,
opt_values: state.updatedTempVal.options,
};
};
export default connect(mapStateToProps, { filteredResultsAction })(
ShowAttemptedQue
);
where am i going wrong?
Everything Seems Fine to me, the Console logs work in the Action and in the Reducer but the Chrome Redux tools show no action being trigged and no state updates.
Here is my Component Class
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { SimpleGrid,Box,Select,Input,InputGroup,InputRightAddon,Text,Heading ,Button,NumberInput,NumberInputField,} from "#chakra-ui/core";
import { Footer } from '../../layout/Main/components';
import {submitUserInput} from '../../utils/actions/userInput'
import PropTypes from 'prop-types';
class UserInput extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this)
this.state = {
yieldStress:0,
thickness:0,
diameter:0,
pMAX:0
}
this.handleChange = this.handleChange.bind(this)
}
handleSubmit=(event)=>{
event.preventDefault();
console.log(this.state);
this.props.submitUserInput(this.state);
}
handleChange=(event)=>{
this.setState({[event.target.name]:event.target.value});
}
render(){
const materialsList = this.props.materials.map((material)=>(
<option value={material.yieldStress} key={material.id}>{material.name}</option>
));
return (
<Box>
<Heading as="h4" size="md">Cylinder Details</Heading>
<Text>{this.props.thickness}</Text>
<form onSubmit={this.handleSubmit} >
<Select placeholder="Select Material of Cylinder" isRequired name="yieldStress" onChange={this.handleChange}>
{materialsList}
</Select>
<SimpleGrid columns={2} spacing={8} padding="16px 0px">
<Box>
<InputGroup>
<InputRightAddon children="(mm)"/>
<Input type="number" placeholder="Thickness of Cylinder" roundedRight="0" isRequired name="thickness" onChange={this.handleChange}/>
</InputGroup>
</Box>
<Box>
<InputGroup>
<InputRightAddon children="(mm)"/>
<Input type="number" placeholder="Diameter of Cylinder" roundedRight="0" isRequired name="diameter"onChange={this.handleChange}/>
</InputGroup>
</Box>
</SimpleGrid>
<SimpleGrid columns={2} spacing={8} padding="0px 0px">
<Box>
<InputGroup>
<InputRightAddon children={<Text paddingTop="12px">(N/mm)<sup>2</sup></Text>} padding="0 4px"/>
<NumberInput precision={2} step={0.2} >
<NumberInputField placeholder="Maximum pressure " roundedRight="0" isRequired name="pMAX" onChange={this.handleChange}/>
</NumberInput>
</InputGroup>
</Box>
<Box>
<InputGroup>
<InputRightAddon children="(mm)"/>
<Input type="number" placeholder="Factor of Saftey" roundedRight="0" isRequired name="FOS"onChange={this.handleChange}/>
</InputGroup>
</Box>
</SimpleGrid>
<Box padding="8px 0" >
<Button variantColor="teal" float="right" border="0" type="submit">Submit</Button>
</Box>
</form>
<Footer />
</Box>
)
}
}
UserInput.protoTypes = {
submitUserInput: PropTypes.func.isRequired,
thickness: PropTypes.string.isRequired,
}
const mapStateToProps = (state) => ({
thickness: state.userInput.thickness
})
const mapDispatchToProps = dispatch => {
return {
submitUserInput: (userInput)=> dispatch(submitUserInput(userInput))
}}
export default connect(mapStateToProps, mapDispatchToProps)(UserInput)
Here is My Action File
import { SUBMIT_REQUEST_SENT,SUBMIT_SUCCESS,SUBMIT_FAILURE} from '../types'
export const submitUserInput = ({yieldStress, FOS, diameter,pMAX,thickness }) => async (dispatch) => {
dispatch(submitRequestSent());
try {
console.log("Printing object in action")
console.log({yieldStress, FOS, diameter,pMAX,thickness }) //This is Printed
dispatch({
type: SUBMIT_SUCCESS,
payload:{yieldStress, FOS, diameter,pMAX,thickness }
}
);
}
catch (error) {
dispatch({
type: SUBMIT_FAILURE,
payload: error.message
})
throw error;
}
}
export const submitRequestSent = () =>
({
type: SUBMIT_REQUEST_SENT,
})
And Here is the UserInput Reducer
import {
SUBMIT_REQUEST_SENT,SUBMIT_SUCCESS,SUBMIT_FAILURE
} from '../../actions/types'
const initialState = {
userInput:{
yieldStress:0,
FOS:0,
diameter:0,
pMAX:0,
thickness:0
}
}
export default function (state = initialState, action) {
switch (action.type) {
case SUBMIT_REQUEST_SENT:
return {
...state,
}
case SUBMIT_SUCCESS:
console.log("Submit has been sucessfull And below is the Payload"); //This is Printed
console.log(action.payload)//This is Printed
return {
...state,
userInput:action.payload
}
case SUBMIT_FAILURE:
return {
...state,
error: action.payload
}
default:
return state;
}
}
And my root Reducer
import {combineReducers} from 'redux';
import authReducer from '../authReducer'
import userInputReducer from '../userInputReducer';
export default combineReducers(
{
auth:authReducer,
userInput:userInputReducer
}
)
I will Appreciate any applicable solution/Explanation..thanks
Within your state you have a property called userInput, which is the state section controlled by userInputReducer. That section has its own property which is also called userInput that stores the actual data. It that what you intended?
If so, you need to map properties like this:
const mapStateToProps = (state) => ({
thickness: state.userInput.userInput.thickness
})
If not, you need to rework your userInputReducer and initialState to remove the double nesting.
Everything Seems Fine to me, the Console logs work in the Action and in the Reducer but the Chrome Redux tools show no action being trigged and no state updates.
This sounds to me like an issue with dispatching an asynchronous thunk action. Redux cannot handle these types of actions without the appropriate middleware. When you create the store, it should be something like this:
import reducer from "./reducer";
import {createStore, applyMiddleware} from "redux";
import thunk from "redux-thunk";
const store = createStore(reducer, applyMiddleware(thunk));
I copy and posted your reducer code with a store set up as above. I used a dummy component ( a button that increments thickness when clicked ) and I was not able to reproduce your issue. That leads me to believe that the issue is in the configuration of the store itself.
I'm trying to submit a form when a user signUp. When the submit button clicked an action creator should executed to start an asynchronous action but actually the submit is not triggered and the action creator is not launched.
actions.ts:
import { ActionTypes } from "./types";
import { SignUpUser, User } from "../apis/authentication";
import { AxiosError } from "axios";
import { Dispatch } from "redux";
export interface ReturnedUser {
username: string;
}
export interface SignUpSuccessAction {
type: ActionTypes.SucceedSignUp;
payload: ReturnedUser;
}
export interface SignUpFailAction {
type: ActionTypes.FailSignUp;
payload: string;
}
export interface SignUpStartAction {
type: ActionTypes.StartSignUp;
}
const signUpStarted = (): SignUpStartAction => ({
type: ActionTypes.StartSignUp
});
const signUpSucceeded = (user: ReturnedUser): SignUpSuccessAction => ({
type: ActionTypes.SucceedSignUp,
payload: user
});
const signUpFailed = (error: string): SignUpFailAction => ({
type: ActionTypes.FailSignUp,
payload: error
});
export const signUpFetch = (user: User) => {
return async (dispatch: Dispatch) => {
dispatch(signUpStarted());
SignUpUser(user).then(
(response: any) => {
const { username } = response;
return dispatch(signUpSucceeded(username));
},
(error: AxiosError) => {
let errorMessage = "Internal Server Error";
if (error.response) {
errorMessage = error.response.data;
}
return dispatch(signUpFailed(errorMessage));
}
);
};
};
reducers/reducer.ts:
import { Action, ActionTypes } from "../actions";
export const SignUpReducer = (state = {}, action: Action) => {
switch (action.type) {
case ActionTypes.SucceedSignUp:
return { ...state, user: action.payload };
case ActionTypes.FailSignUp:
return { ...state, error: action.payload };
default:
return state;
}
};
reducers/index.ts:
import { SignUpReducer } from "./signUp";
import { combineReducers } from "redux";
export const reducer = combineReducers({
signUp: SignUpReducer
});
index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import SignUp from "./containers/Signup/SignUp";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { reducer } from "./reducers/index";
const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
const App = () => <SignUp />;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
SignUp.tsx:
import React, { useState } from "react";
import Button from "#material-ui/core/Button";
import { connect } from "react-redux";
import { Form, Field } from "react-final-form";
import { makeStyles, Theme, createStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import CardWrapper from "../../components/CardWrapper";
import PasswordField from "../../components/Password";
import TextField from "../../components/TextField";
import { validate, submit } from "./validation";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
container: {
padding: 16,
margin: "auto",
maxWidth: "100%",
flexGrow: 1
},
paper: {
padding: 16
},
item: {
marginTop: 16
}
})
);
const SignUp = () => {
const classes = useStyles();
const [showPassword, setPassword] = useState(false);
const handleClickShowPassword = () => {
setPassword(!showPassword);
};
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
return (
<div className={classes.container}>
<Form
onSubmit={submit}
validate={validate}
render={({ handleSubmit, form, submitting, pristine }) => (
<form onSubmit={handleSubmit}>
<CardWrapper title='SignUp Form'>
<Grid container justify='center' spacing={3}>
<Grid item md={12}>
<Field fullWidth required name='username'>
{props => (
<TextField
label='Username'
type='text'
value={props.input.value}
onChange={props.input.onChange}
onBlur={props.input.onBlur}
meta={props.meta}
fullWidth={true}
/>
)}
</Field>
</Grid>
<Grid item md={12}>
<Field fullWidth required name='email'>
{props => (
<TextField
label='Email'
type='email'
value={props.input.value}
onChange={props.input.onChange}
onBlur={props.input.onBlur}
meta={props.meta}
fullWidth={true}
/>
)}
</Field>
</Grid>
<Grid item md={12}>
<Field fullWidth required name='password'>
{props => (
<PasswordField
value={props.input.value}
handleChange={props.input.onChange}
showPassword={showPassword}
handleClickShowPassword={handleClickShowPassword}
handleMouseDownPassword={handleMouseDownPassword}
fullWidth={true}
onBlur={props.input.onBlur}
meta={props.meta}
/>
)}
</Field>
</Grid>
<Grid item className={classes.item}>
<Button
type='button'
variant='contained'
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</Button>
</Grid>
<Grid item className={classes.item}>
<Button
variant='contained'
color='primary'
type='submit'
disabled={submitting || pristine}
>
Submit
</Button>
</Grid>
</Grid>
</CardWrapper>
</form>
)}
/>
</div>
);
};
export default connect()(SignUp);
validation.ts:
interface SignUpValues {
email: string;
password: string;
username: string;
}
const submit = (values: SignUpValues) => {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return signUpFetch(user);
};
export { submit };
I find a similar question posted about the same issue described by Redux Dispatch Not Working in Action Creator but the answer does not fix my problem. Does I make something wrong when linking the different component with redux?
It wont dispatch because in component You didnt dispatch Your function
return signUpFetch(user)
Instead Connect the component with Redux and dispatch the function
in Index.tsx
import { connect } from 'react-redux';
const mapDispatchToProps = {
submit
};
export default connect(null, mapDispatchToProps)(SignUp);
And access it with
this.props.submit
Add dispatch in Submit function
const submit = (values: SignUpValues) =>(dispatch, getState)=> {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return dispatch(signUpFetch(user));
};
Whenever you need to update redux state, dispatch the function from where it is also called and also in the actions.
You need to connection the component to the store when you do the dispatch:
import { connect } from 'react-redux';
const submit = (values: SignUpValues) => {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return this.props.signUpFetch(user);
};
export const connectedSubmit = connect(null, {signUpFetch})(submit);
import { validate, connectedSubmit as submit } from "./validation";
And also you can just return at SignUpUser
export const signUpFetch = (user: User) => {
return async (dispatch: Dispatch) => {
dispatch(signUpStarted());
return SignUpUser(user).then(
(response: any) => {
const { username } = response;
dispatch(signUpSucceeded(username));
},
(error: AxiosError) => {
let errorMessage = "Internal Server Error";
if (error.response) {
errorMessage = error.response.data;
}
dispatch(signUpFailed(errorMessage));
}
);
};
}
I have this react app using redux but I can't figure out why the action creator is not calling the reducer.
I cant see the console log inside the LOGGED_IN case in the authReducer file.
the action is called userLogedIn and can be found in the Login.js class
Any help would be great!
thnx
this is the code:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import App from './App';
import reducers from './reducers';
const store = createStore(
reducers,
compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Login.js - the class
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Redirect, Link } from 'react-router-dom';
import {connect} from 'react-redux';
import { userLogedIn } from '../../actions';
import {
Button,
Form,
FormGroup,
FormControl,
Col,
Checkbox,
ControlLabel,
HelpBlock,
Container,
Row
} from 'react-bootstrap';
class LoginForm extends Component {
onSubmitLogin = (event) => {
// let auth = this.state.auth;
event.preventDefault();
fetch('http://127.0.0.1/react/calc/api/user_switch/' + this.state.username +
'/'+ this.state.password )
.then(response => response.json())
.then(json => {
console.log('json ',json)
if(json.count > 0)
{
this.props.userLogedIn(this.props)
}
})
.catch(error => console.log('parsing faild', error))
}
onChange(event){
this.setState({
[event.target.name]: event.target.value
})
}
redirectUser = () =>
{
if(this.props.user.auth)
{
return <Redirect to='/mechinasetup' data={this.state.data} />
}
}
render() {
console.log();
return (
<Container id="LoginForm" className="yellow-bg">
<Row className="show-grid">
<Col xs={8} md={4}>
<Form>
<FormGroup controlId="formHorizontalusername">
<Col xs={12} sm={3} componentclass={'aa'}>
דואר אלקטרוני:
</Col>
<Col xs={12} sm={9}>
<FormControl
ref="username"
name="username"
type="text"
onChange={this.onChange.bind(this)}
placeholder="הקלד דואר אלקטרוני"/>
</Col>
</FormGroup>
<FormGroup controlId="formHorizontalPassword">
<Col xs={12} sm={3} componentclass={'cc'}>
סיסמא:
</Col>
<Col xs={12} sm={9}>
<FormControl ref="password" name="password" type="password" onChange={this.onChange.bind(this)} placeholder="הקלד סיסמא"/>
</Col>
</FormGroup>
<FormGroup>
<Col >
{this.redirectUser(this)}
<Button onClick={this.onSubmitLogin} type="submit" className="full-width-btn" id="loginSubmit">התחבר</Button>
</Col>
</FormGroup>
</Form>
</Col>
</Row>
</Container>
);
}
}
const mapStateToProps = (state) =>{
return{
user: state.user
}
}
export default connect(mapStateToProps, {userLogedIn})(LoginForm);
action:
import { LOGGED_IN } from '../consts';
export const userLogedIn = (state) => {
const action = {
type: LOGGED_IN,
state
}
console.log(state, ' action is auth ');
return action
}
authReducer.js:
import { LOGGED_IN } from '../consts';
const initialState = {
username: '',
password: '',
data: [],
auth: false
}
export default (state = initialState, action) => {
switch(action.type){
case LOGGED_IN:
console.log('LOGGED_IN');
return{
...state,
auth: true
}
default:
return state;
}
}
reducers.js:
import { combineReducers } from 'redux';
import manageCoursesReducer from './manageCoursesReducer';
import authReducer from './manageCoursesReducer';
export default combineReducers({
user: authReducer
})
As you know by now, here is your problem:
import { combineReducers } from 'redux';
import manageCoursesReducer from './manageCoursesReducer';
import authReducer from './manageCoursesReducer';
export default combineReducers({
user: authReducer
})
You are calling the same file in the relative path for two different imports.
I think that the problem is you're not dispatching the action anywhere. try this on Login.js:
const mapStateToProps = (state) =>{
return{
user: state.user
};
};
const mapDispatchToProps = dispatch => {
return {
userLogedIn: (params) => dispatch(userLogedIn(params))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
Let me know if it helped.
The mistake was that I called manageCoursesReducer twice for two different reducers.
import manageCoursesReducer from './manageCoursesReducer';
import authReducer from './manageCoursesReducer';
instead of
import manageCoursesReducer from './manageCoursesReducer';
import authReducer from './authReducer';
now it works