I am learning React-Redux and trying to get more comfortable with it by implementing things in various ways. I have a login form where I want to display an error message if the username/password is invalid. I have created config file with the required user details. I am calling an authenticate api to generate a JWT token for the logged in user.So, the token you get as response of the authenticate api will have the logged in user details. I have done something like below but I see I am able to successfully login every time and not able to display any error message when I try to provide any random/wrong user name. I have commented out the componetWillreceiveProps function now but would like to understand what I am doing wrong.
My Log in Comp-
import React from "react";
import Header from "./header";
import Footer from "./footer";
import { connect } from "react-redux";
import { createLogIn, setAuthError } from "../actions/action";
const axios = require("axios");
import jwtdata from "../config/jwtdata";
class Login extends React.Component {
constructor() {
super();
this.state = {
account: { user: "", password: "" }
};
}
handleAccountChange = ({ target: input }) => {
const account = { ...this.state.account };
account[input.name] = input.value;
this.setState({ account });
};
handleLoginForm = e => {
e.preventDefault();
let postLoginData = {};
const userName = this.state.account.user;
// call to action
this.props.dispatch(createLogIn(postLoginData, userName));
this.props.dispatch(setAuthError())
this.props.history.push("/intro");
};
// componentWillReceiveProps(nextProps) {
// if (nextProps.authStatus){
// this.props.history.push("/intro");
// }
// }
render() {
const { account } = this.state;
return (
<div className="intro">
<Header />
<form onSubmit={this.handleLoginForm}>
<div className="content container">
<div className="profile" />
<div className="row">
<div className="col-xs-12">
<input
type="text"
autoFocus
placeholder="username"
name="user"
value={account.user}
onChange={this.handleAccountChange}
/>
<input
type="password"
placeholder="password"
name="password"
value={account.password}
onChange={this.handleAccountChange}
/>
<button
className={
"loginButton " +
(account.user && account.password
? "not-disabled"
: "disabled")
}
disabled={!account.user && !account.password ? true : false}
>
<span>Sign in</span>
</button>
</div>
{!this.props.authStatus ? (
<p className="login-error">
Authorization Failed. Please try again!
</p>
) : (
<p />
)}
</div>
</div>
</form>
<Footer />
</div>
);
}
}
const mapStateToProps = state => ({
authStatus: state.root.authStatus
});
export default connect(mapStateToProps)(Login);
Action creator-
export const createLogIn = (postLoginData, userName) => (dispatch) => {
console.log('>>> ', userName);
console.log('authenticating');
console.log(btoa(JSON.stringify(jwtdata)));
localStorage.setItem("UserData", btoa(JSON.stringify(jwtdata[userName])))
// dispatch({
// type: SET_AUTH_ERROR,
// payload: false
// })
axios({
method: "POST",
url: "/authenticateUrl",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: postLoginData
})
.then (response => {
dispatch({
type: API_LOG_IN,
payload: response.data
})
localStorage.setItem('AccessToken', response.data.jwt_token);
})
.catch( error => {
console.log("in catch block");
});
}
export const setAuthError = () => {
console.log('inside actions');
return {
type: SET_AUTH_ERROR,
payload: "Authorization Error"
}
}
Reducer-
const initialState = {
authStatus: true
}
const reducerFunc = (state = initialState, action) => {
switch (action.type) {
case API_LOG_IN:
console.log('reducers');
return {...state, logIn: action.payload}
case SET_AUTH_ERROR:
console.log('inside Auth reduccer');
return {...state,authStatus: action.payload}
default: return {...state}
}
}
export default reducerFunc;
I am trying to add a check inside componentWillReceiveProps but that doesn't seem to be working.Instead it always displays me the error message even when the user name is same as the config file.What I want is to display some message like "Authorization failed" if I try to hit the sign in button with wrong User credentials.
!this.props.authStatus ? (
Seems like this line is the problem. Since your authStatus is either "undefined" when no error occurred or "Authentication failed".
Related
I am trying to develop a flexible authentication system on Next.js that can use a Spring (Java) API backend. The endpoints function perfectly using Postman. The API also provides its own JWT. I want to sign in registered users using the API endpoint. This also means I need a way to use the JWT from the server to authenticate the user trying to sign in.
Following the documentation for both Next_auth and iron-sessions has been very confusing. The API works fine. Next_auth in particular seems to provide limited support for this type of authentication.
I've researched quite a few posts, tutorials and even posted this question. This question comes the closest to what I'm trying to understand, but it deals with a post sign in state and the process looks a bit confusing. This question seems to say that it's quite complicated to perform custom authentication on Next and it's always best to use frameworks.
Am I missing something here or is it very complicated to get Next js to work with external APIs and JWT? I don't need the full stack functionality that Next has to offer. I also don't want to be forced to authenticate through Google, Twitter, FB, etc.
I need something like this, which was created using React and uses REST API endpoints to sign in registered users and manage the respective user sessions.
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("username", enteredEmail);
urlencoded.append("password", enteredPassword);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch(API_LOGIN_URL, requestOptions)
.then((res) => {
setIsLoading(false);
if (res.ok) {
return res.json();
} else {
return res.json().then((data) => {
let errorMessage = 'Authentication failed!';
throw new Error(errorMessage);
});
}
})
.then((data)=> {
authCtx.login(data.access_token);
const processedData = JSON.stringify(data);
console.log("Admin status "+ processedData);
for(let i = 0; i < processedData.length; i++) {
if(processedData.includes("ROLE_SUPER_ADMIN")) {
console.log("Found Admin");
authCtx.adminAccess(true);
}
if(processedData.includes("ROLE_USER")) {
console.log("Found User");
break;
}
else {
console.log("Not Found");
}
}})
.catch((err) => {
alert(err.message);
});
}
};
return (
<section className={classes.auth}>
<h1>{isLogin ? 'Login' : 'Sign Up'}</h1>
<form onSubmit={submitHandler}>
<div className={classes.control}>
<label htmlFor='email'>Your Email</label>
<input type='email' id='email' required ref={emailInputRef} />
</div>
<div className={classes.control}>
<label htmlFor='password'>Your Password</label>
<input type='password' id='password' required ref={passwordInputRef} />
</div>
<div className={classes.actions}>
{!isLoading && <button>{isLogin ? 'Login' : 'Create Account'}</button>}
{isLoading && <p>Sending request</p>}
<button
type='button'
className={classes.toggle}
onClick={switchAuthModeHandler}
>
{isLogin ? 'Create new account' : 'Login with existing account'}
</button>
</div>
</form>
</section>
);
};
export default AuthForm;
I'd like to do something similar in Next.js without working according to the rules of frameworks / libraries like next_auth.
I would really appreciate any guidance, (advice, tutorials, etc) that explain how to use a post method to an API endpoint to look up a username and password.
I'd also like to know how to use the JWT generated from the API to complete the process and authenticate the user. I can put this part in another question. For this question I'd be happy even if I know how to sign in by looking up username and password, using the API endpoints I've described. In Next.js, I've only seen authentication done using frameworks like Next_auth or iron-sessions. I haven't seen the the type of custom authentication methods you'd find in React (described above). Therefore, I'd like to know:
Do we have to use Next_auth or iron-sessions for authentication? Are there any examples of custom Next js authentication methods that don't rely on these frameworks and play nicely with backend APIs and JWT such as Spring?
Thanks in advance for any help.
With great help from Dream_Cap, who directed me to a relevant article and his own node.js code, the answer is that it is totally possible to write a custom authentication method without relying on any frameoworks such as next_auth.
The crux of the solution is that Next js can use React Context, as a a Higher Order Component (HOC), to hold the authentication state and persist changes in the user session accordingly. This is a somewhat different approach from using the [...nextuth].js approach which is designed to catch all requests.
This alternative method basically means you can use almost the same approach as you would in a normal React application, but slightly modified to a Next.js context:
let logoutTimer;
let initialToken;
let initialAdminToken;
const AuthContext = React.createContext({
token: '',
admintoken: '',
isLoggedIn: false,
isAdmin: false,
login: (token) => { },
adminAccess: (admintoken) => { },
logout: () => { },
});
const calcTimeRemaining = (expirationTime) => {
const currentTime = new Date().getTime();
const adjExpireTime = new Date(expirationTime).getTime();
const remaingDuration = adjExpireTime - currentTime;
return remaingDuration;
}
export const AuthContextProvider = (props) => {
const authCtx = useContext(AuthContext);
const isAdmin = authCtx.isAdmin;
const [token, setToken] = useState(initialToken);
const [admintoken, setAdminToken] = useState(initialAdminToken);
const userIsLoggedIn = !!token;
const userHasAdmin = !!admintoken;
useEffect(() => {
initialToken = localStorage.getItem('token');
initialAdminToken = localStorage.getItem('admintoken');
if(initialAdminToken !== initialToken) {
setToken(initialToken);
} else {
setToken(initialToken);
setAdminToken(initialAdminToken);
}
}, [initialToken, initialAdminToken]);
const logoutHandler = () => {
setToken(null);
setAdminToken(null);
localStorage.removeItem('token');
localStorage.removeItem('admintoken');
};
const loginHandler = (token) => {
if(admintoken == null) {
setToken(token);
localStorage.setItem('token', token);
} else {
setToken(token);
localStorage.setItem('token', token);
setAdminToken(token);
localStorage.setItem('admintoken', token);
}
// const remainingTime = calcTimeRemaining(expirationTime);
setTimeout(logoutHandler, 300000);
};
const adminTokenHandler = (admintoken) => {
setAdminToken(admintoken);
localStorage.setItem('admintoken', admintoken);
}
const contextValue = {
token: token,
admintoken: admintoken,
isAdmin: userHasAdmin,
isLoggedIn: userIsLoggedIn,
adminAccess: adminTokenHandler,
login: loginHandler,
logout: logoutHandler,
};
return (
<AuthContext.Provider value={contextValue}>
{props.children}
</AuthContext.Provider>
);
};
export default AuthContext;
The login form:
const AuthForm = () => {
const emailInputRef = useRef();
const passwordInputRef = useRef();
const [isLoading, setIsLoading] = useState(false);
const [isAdmin, setIsAdmin] = useState(false);
const router = useRouter();
const authCtx = useContext(AuthContext);
const submitHandler = (event) => {
event.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredPassword = passwordInputRef.current.value;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("username", enteredEmail);
urlencoded.append("password", enteredPassword);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch(API_LOGIN_URL, requestOptions)
.then(async (res) => {
setIsLoading(false);
if (res.ok) {
return res.json();
} else {
const data = await res.json();
let errorMessage = 'Authentication failed!';
throw new Error(errorMessage);
}
})
.then((data) => {
authCtx.login(data.access_token);
router.replace('/');
const processedData = JSON.stringify(data);
for (let i = 0; i < processedData.length; i++) {
if (processedData.includes("ROLE_SUPER_ADMIN")) {
console.log("Found Admin");
authCtx.adminAccess(data.access_token);
} else {
console.log("Found User");
authCtx.adminAccess(null);
}
}
})
.catch((err) => {
alert(err.message);
});
};
return (
<section className={classes.auth}>
<h1>Login</h1>
<form onSubmit={submitHandler}>
<div className={classes.control}>
<label htmlFor='email'>Your Email</label>
<input type='email' id='email' required ref={emailInputRef} />
</div>
<div className={classes.control}>
<label htmlFor='password'>Your Password</label>
<input type='password' id='password' required ref={passwordInputRef} />
</div>
<div className={classes.actions}>
{!isLoading && <button>Login</button>}
{isLoading && <p>Sending request</p>}
</div>
</form>
</section>
);
};
To protect the routes:
const ProtectRoute = ({ children }) => {
const authCtx = useContext(AuthContext);
const isLoggedIn = authCtx.isLoggedIn;
if (!isLoggedIn && typeof window !== 'undefined' && window.location.pathname == '/') {
return <HomePage />;
} else {
if (!isLoggedIn && typeof window !== 'undefined' && window.location.pathname !== '/auth') {
return <RestrictedSection />;
}
else {
return children;
}
}
}
export default ProtectRoute;
Finally, the route protection is wrapped around the main _app.js file:
function MyApp({ Component, pageProps }) {
// const ProtectedPages = dynamic(()=> import ('../store/ProtectRoute'));
return (
<AuthContextProvider>
<Layout>
<ProtectRoute>
<Component {...pageProps} />
</ProtectRoute>
</Layout>
</AuthContextProvider>
)
};
export default MyApp
pls am currently building a simple UI using react on codesandbox. I just want the user to be able to enter an API end point in a text field and have the output(response data) rendered on a text area. Below is my codesandbox project link:
https://codesandbox.io/s/dry-surf-6ygc5?file=/src/components/PostList.jsx. Your input will be highly appreciated!
It seems like your missed to the target value of input text in the OnChange event for the Input. Please see the below code if that helps.
<input
name="inputApi"
onChange={(e) => this.setState({ apiText: e.target.value })}
type="text"
/>
I have removed few of your code. Also i didn't do other functionality like error handling. Please add a try catch block to Async block
submitHandler = async (e) => {
e.preventDefault();
try {
const resp = await axios.get(
`https://jsonplaceholder.typicode.com/${this.state.apiText}`
);
// console.log(resp.data);
this.setState({ posts: resp.data });
} catch (error) {
this.setState({ errorMsg: error.message });
}
};
Full code is here below.
import React, { Component } from "react";
import axios from "axios"; //for making API calls
class PostList extends Component {
constructor(props) {
super(props);
/**
* the lines below are unneccessary
* as the functions are arrow functions
* and require no binding
* value={this.state.api}
*/
this.state = {
posts: [],
errorMsg: "",
api: {},
apiText: ""
};
} //end of constructor
submitHandler = async (e) => {
e.preventDefault();
try {
const resp = await axios.get(
`https://jsonplaceholder.typicode.com/${this.state.apiText}`
);
// console.log(resp.data);
this.setState({ posts: resp.data });
} catch (error) {
this.setState({ errorMsg: error.message });
}
};
render() {
const { posts, errorMsg } = this.state; //destructure the state object
//console.log(res.data);
return (
<div>
<form onSubmit={this.submitHandler}>
<input
name="inputApi"
onChange={(e) => this.setState({ apiText: e.target.value })}
type="text"
/>
<input type="submit" />
</form>
List of Posts: {posts.length}
{posts.length ? (
<div>
<textarea value={this.state.posts[0].title} readOnly />
</div>
) : null}
{errorMsg ? <div>{errorMsg}</div> : null}
</div>
); //endOfReturn
} //endOfRender
} //endOfPostList
export default PostList;
/**posts.map((post) => <div key={post.id}>{post.title}</div>)*/
You have a small error getting the value in your submitHandler.
Instead of the user input value, you pass the string "e.target.value", which is not true.
const resp = axios.get("e.target.value");
Use it like this instead
const inputLink = e.target[0].value;
const resp = axios.get(inputLink);
It also makes no sense to store the result of calling the axios.get function in the component state.
Immediately after the call, you can use then and catch on the result of calling axios.get
axios
.get(inputLink)
.then((res) => {
this.setState({ posts: res.data });
})
.catch((error) => {
this.setState({
errorMsg: "error retrieving data"
});
});
Thus, a minimal working component will look something like this.
I have a handleLogin function in an auth.js file, I would like to retrieve the errors received in the .catch and transmit them in my Alert.js file in order to display the errors in an alert in Login.js...
This is my handleLogin function on auth.js
export const handleLogin = async ({ email, password }) => {
const user = await ooth.authenticate('local', 'login', {
username: email,
password: password,
}).catch(e => {
alert(e.message)
});
await navigate(`/app/profile`);
if (user) {
return setUser({
id: user._id,
username: `jovaan`,
name: `Jovan`,
email: user.local.email,
avatar: `3`,
telephone: `0788962157`,
bio: `I'm a front-end dev`
})
}
return false
}
My Alert.js
import React from "react";
import { Alert } from "shards-react";
export default class DismissibleAlert extends React.Component {
constructor(props) {
super(props);
this.dismiss = this.dismiss.bind(this);
this.state = { visible: true, message: "Message par défaut" };
}
render() {
return (
<Alert dismissible={this.dismiss} open={this.state.visible} theme="success">
{this.message()}
</Alert>
);
}
dismiss() {
this.setState({ visible: false });
}
message() {
return this.state.message
}
}
I imported my Alert.js into my Login page, so I currently have the default message
You will need to somehow pass the results of the failed login via props wherever you have the <DismissableAlert /> in your code, which I'm presuming would be at /login or similar. My guess would be to do something like this, by passing the error via the 'state' option that navigate provides:
const error = null;
const user = await ooth.authenticate('local', 'login', {
username: email,
password: password,
}).catch(e => {
error = e
console.err(e.message)
});
if(error) {
await navigate(`/login`, {
state: { error: error },
});
}
Then in your LoginPage component (or whatever it is called), you should then have access to the result of the error as props that you can then pass down to the Alert:
render() {
const {error} = this.props
return(
<div>
<LoginForm />
{error &&
<DismissibleAlert message={error.message} />
}
</div>
)
}
Or something along those lines, depending on your components. I notice you have a default message in the DismissableAlert, so this is just an example to show that you could pass the error in to use it to show a relevant message.
I am pretty new to MERN stack. I am trying to setup user authentication using jwt.
The problem is only occurring when I am using the front end to login. When I using POST man to make an http request, login successful is succesfull
However when I login using email and password I get the following error:
console
Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at authActions.js:40
I know it is showing where the error is but I am still unable to fix it.
authActions.js
import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";
import { GET_ERRORS, SET_CURRENT_USER, USER_LOADING } from "./types";
// Register User
export const registerUser = (userData, history) => dispatch => {
axios
.post("/api/users/register", userData)
.then(res => history.push("/login")) // re-direct to login on successful register
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
// Login - get user token
export const loginUser = userData => dispatch => {
axios
.post("/api/users/login", userData)
.then(res => {
// Save to localStorage
// Set token to localStorage
const { token } = res.data;
localStorage.setItem("jwtToken", token);
// Set token to Auth header
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
// Set current user
dispatch(setCurrentUser(decoded));
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
// Set logged in user
export const setCurrentUser = decoded => {
return {
type: SET_CURRENT_USER,
payload: decoded
};
};
// User loading
export const setUserLoading = () => {
return {
type: USER_LOADING
};
};
// Log user out
export const logoutUser = () => dispatch => {
// Remove token from local storage
localStorage.removeItem("jwtToken");
// Remove auth header for future requests
setAuthToken(false);
// Set current user to empty object {} which will set isAuthenticated to false
dispatch(setCurrentUser({}));
};
Following is my code for login front end.
login.jsx
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
componentDidMount() {
// If logged in and user navigates to Login page, should redirect them to dashboard
if (this.props.auth.isAuthenticated) {
this.props.history.push("/dashboard");
}
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
componentWillReceiveProps(nextProps) {
if (nextProps.auth.isAuthenticated) {
this.props.history.push("/dashboard"); // push user to dashboard when they login
}
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
};
handleSubmit = event => {
event.preventDefault();
console.log("Submit called");
const userData = {
email: this.state.email,
password: this.state.password
};
this.props.loginUser(userData);
};
render() {
const errors = this.state;
return (
<div className="Login">
<form onSubmit={this.handleSubmit}>
<FormGroup controlId="email" bs="large">
<FormLabel>Email</FormLabel>
<span className="red-text">{errors.emailnotfound}</span>
<FormControl
autoFocus
type="email"
value={this.state.email}
onChange={this.handleChange}
className={classnames("", {
invalid: errors.email || errors.emailnotfound
})}
/>
</FormGroup>
<FormGroup controlId="password" bs="large">
<FormLabel>Password</FormLabel>
<span className="red-text">
{errors.password}
{errors.passwordincorrect}
</span>
<FormControl
value={this.state.password}
onChange={this.handleChange}
type="password"
className={classnames("", {
invalid: errors.password || errors.passwordincorrect
})}
/>
</FormGroup>
<Button
block
bs="large"
disabled={!this.validateForm()}
type="submit"
>
Login
</Button>
<br />
<p> Dont have account ? </p>
<Link to="/register">
{" "}
<p style={{ color: "blue" }}> Join Us </p>{" "}
</Link>
</form>
<br />
</div>
);
}
}
I have left out some import statements to shorten the code.
The error is on line 40, wich is in payload: err.response.data.
If it says
Cannot read property 'data' of undefined
It means that err.response is ndefined.
You should do some checking before passing that. Maybe it's returning a different error that doesn't have .response.
Try console.log(err) to check what is inside of it.
It looks that you don't stringify the data before you send it. Require the qs library and change your code to that:
axios
.post("/api/users/register", qs.stringify( userData ))
.then(res => history.push("/login")) // re-direct to login on successful register
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
You can also check that the data is not sent correctly by looking the Network tab in your Browser's Dev Tools. I expect to send the data in a wrong format. I hope that I am correct.
You need to update your code from
onSubmit={this.handleSubmit} to onSubmit={()=>this.handleSubmit()}
And
onChange={this.handleChange}to onChange={()=>this.handleChange()}
because of this your password and email are not getting set to state and your API axios.post("/api/users/login", userData) is throwing exception.
I have to update my user's profile that has 5 fields name, bio address, image, and gender. I have created perfectly working API on Django that uses auth Knox token for authentication.
I have stored the auth token during login in the state. Of which the reducer looks like this:
case 'LOGIN_SUCCESSFUL':
case 'REGISTRATION_SUCCESSFUL':
localStorage.setItem("token", action.data.token);
return {...state, ...action.data, isAuthenticated: true, isLoading: false, errors: null};
I can access the token later on like this:
let headers = {"Content-Type": "application/json"};
let {token} = getState().auth;
if (token) {
headers["Authorization"] = `Token ${token}`;
}
My question is:
How can I make a form that takes this token as a header and makes a post request? What will be the reducers and what will be the actions?
class Profile extends Component {
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(e) {
e.preventDefault()
console.log(this.props.Name)
}
change = e => {
console.log(e.target.name)
values.push(e.target.value)
[e.target.name]: e.target.value
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<label htmlFor="Name">Name</label>
<input name="Name" onChange={e => this.change(e)} component="input" type="text" />
</div>
<div>
<label htmlFor="Bio">Bio</label>
<input name="Bio" component="input" onChange={e => this.change(e)} type="text" />
</div>
<div>
<label htmlFor="Address">Address</label>
<input name="Address" component="input" onChange={e => this.change(e)} type="text" />
</div>
<button type="submit">Submit</button>
</form>
)
}
}
const mapStateToProps = (state) => {
return {
profile: state.user,
}
}
const mapDiapatchToProps = (dispatch) => {
return {
updateprofile: (values) => dispatch(updateprofile(values))
}
}
export default connect(mapStateToProps, mapDiapatchToProps)(Profile);
I tried this but I got confused how to send values to action?
Or Should I have to use redux-form?
I want to make a put request on this API: api/update/profile/${id}
Please help me out.
You need to use an external library to make a HTTP call, like Axios.
In your action file you need to create the function updateProfile. Inside this function you need to make the HTTP call using Axios, or wathever you want. With axios your function will be something like this:
function updateProfile() {
return (dispatch) => {
axios({
method:'get',
url:'[YOUR API ADDRESS]',
headers: {Authorization: '[YOUR TOKEN]'},
data: {
name: 'bruce',
lastName: 'bane'
}
}).then(function(response) {
dispatch({
type: UPDATE_PROFILE,
payload: response
});
});
return null
}
}
In youe Profile component you need to change the mapDispatchToProps function to call the updateProfile function from the action file, like this:
const mapDispatchToProps = (dispatch) => {
return {
updateprofile: (values) => dispatch(profileActions.updateprofile(values))
}
}
Note: I didn't tested this code, but it will be something close to this. Hope it could help.