Unable to fetch github users using redux - reactjs

I am trying to fetch github users on providing username, but unable to
fetch. Can anyone tell what I am missing , as I see the code seem
perfect.
I am trying to fetch github users on providing username, but unable to
fetch. Can anyone tell what I am missing , as I see the code seem
perfect.
Below is my code for component, action, reducer
class Navbar extends Component {
constructor(props) {
super(props);
this.state = {
userName: ""
};
this.searchUser = this.searchUser.bind(this);
this.onChange = this.onChange.bind(this);
}
componentDidMount(){
console.log(this.props.users)
}
searchUser(e) {
e.preventDefault();
this.props.searchUser(this.state.userName);
this.setState({ userName: "" });
}
onChange(e) {
this.setState({ [e.target.id]: e.target.value }, () =>
console.log(this.state.userName)
);
}
render() {
return (
<nav className="navbar fixed-top navbar-expand-md navbar-light bg-primary">
<div className="container">
<h4>Github Search</h4>
<form className="form-inline my-1 my-lg-0" onSubmit={this.searchUser}>
<div className="input-group add-on">
<input
type="search"
className="form-control mr-sm-2 border-right-0 border"
id="userName"
placeholder="Search User..."
aria-label="Search"
onChange={this.onChange}
value={this.state.userName}
/>
</div>
</form>
</div>
</nav>
);
}
}
const mapStateToProps = state => {
return {
users: state.users
};
};
export default connect(
mapStateToProps,
{ searchUser }
)(Navbar);
-------------------------------------
export const searchUser = userName => dispatch => {
console.log("----" + userName);
fetch("https://api.github.com/search/users?q=" + userName)
.then(res => res.json())
.then(users =>
dispatch({
type: "FETCH_USERS",
payload: users.items
})
);
};
--------------------------------------------
export default function(state = { users: [] }, action) {
switch (action.type) {
case "FETCH_USERS":
return {
...state,
users: action.payload
};
default:
return state;
}
}
--------------------------------------------
I am able to pass submitted username to actions but after dispatch
there seem some error.

Related

React redux thunk return dispatch not called

I am developing a web application which I would like to use react redux. but my app is not dispatching. If I want to careate a new project and send request to action to dispatch it does not dispatch.
class CreateProject extends Component {
state = {
title: '',
content: ''
}
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault();
// console.log(this.state);
this.props.createProject(this.state);
}
render() {
return (
<div className="container">
<form className="white" onSubmit={this.handleSubmit}>
<h5 className="grey-text text-darken-3">Create a New Project</h5>
<div className="input-field">
<input type="text" id='title' onChange={this.handleChange} />
<label htmlFor="title">Project Title</label>
</div>
<div className="input-field">
<textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
<label htmlFor="content">Project Content</label>
</div>
<div className="input-field">
<button className="btn pink lighten-1">Create</button>
</div>
</form>
</div>
)
}
Projectreducer.js
const projectReducer = (state = initState, action) => {
switch (action.type) {
case 'CREATE_PROJECT':
console.log('create project', action.project);
return state;
case 'CREATE_PROJECT_ERROR':
console.log('çreate project error', action.err);
return state;
default:
return state;
}
};
export default projectReducer;
I have consoled on the function on project action is show the item on the console.
When I try consule of the return statement nothing happens
projectAction.js
export const createProject = (project) => {
return { type: 'CREATE_PROJECT', project }
return (dispatch, getState, {getFirebase, getFirestore}) => {
make async call to database
const firestore = getFirestore();
console.log(firestore);
firestore.collection('projects').add({
...project,
authFirstName: ' nm',
authorLastName: 'kjbbggh',
authorId: 12345,
createdAt: new Date()
}).then(()=>{
dispatch({ type: 'CREATE_PROJECT', project });
}).catch((err) => {
dispatch({type: 'ÇREATE_PROJECT_ERROR', err})
})
}
};

How to set state object values into redux store

I have form where I have 2 input textboxes. On its change handler I am setting their respective values into state object. However I want to store those 2 values into redux store so that I can use it on multiple components. Is there anyway where I can store those 2 input values into state and in redux store as well. Below is my login componet code. Thanks in advance.
import React from "react";
import { connect } from "react-redux";
import * as loginAction from "../redux/actions/LoginAction";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",//want to have this value in redux store so that I can use it in multiple components
password: "",
errorUsername: null,
errorPassword: null,
};
this.handleValidation = this.handleValidation.bind(this);
this.handleChange = this.handleChange.bind(this);
}
//assign textbox values to props
handleChange = (e) => {
this.setState({
[e.target.name]: [e.target.value],
});
};
//handle input validation
handleValidation = (event) => {
if (!this.state.username) {
this.setState({ errorUsername: "Please enter User Name" });
event.preventDefault();
}
if (!this.state.password) {
this.setState({ errorPassword: "Please enter Password" });
event.preventDefault();
}
if (this.state.password && this.state.username) {
this.setState({ errorUsername: null, errorPassword: null });
let postData = {
username: this.state.username[0],//want to have this value in redux store so that I can use it in multiple components
password: this.state.password[0],
};
event.preventDefault();
//dispatching an action
this.props.dispatch(loginAction.checkLogin(postData, this.props.history));
}
};
render() {
return (
<div className="d-flex flex-column">
<div className="d-flex globalStyle">
<div className="w-100 justify-content-start p-5">
<div className="p-10 bg-white">
<div className="Login">
<form>
<div className="d-flex flex-column">
<div>Login</div>
<div className="d-flex flex-row">
<div>
<b>User name</b>
</div>
</div>
<div>
<input
type="username"
name="username"
className="inputText"
id="exampleInputUserName"
value={this.props.userName}
onChange={this.handleChange}
placeholder="Enter User Name"
></input>
</div>
<div className="text-danger d-flex flex-row p-2 ml-2">
{this.state.errorUsername && (
<div>{this.state.errorUsername}</div>
)}
</div>
<div className="d-flex flex-row">
<div>
<b>Password</b>
</div>
</div>
<div className="d-flex flex-row p-2 ml-2">
<input
type="password"
name="password"
className="inputText"
value={this.props.password}
onChange={this.handleChange}
placeholder="Enter Password"
></input>
</div>
<div className="text-danger d-flex flex-row p-2 ml-2">
{this.state.errorPassword && (
<div>{this.state.errorPassword}</div>
)}
</div>
<div className="d-flex flex-row justify-content-around p-2 ml-2">
<button
type="submit"
onClick={this.handleValidation}
className="button-style"
>
Login
</button>
</div>
</div>
<div>
<br></br>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
userDetails: state.userDetails,
};
}
export default connect(mapStateToProps)(Login);
Mu login action code is
const getUserDetailsSuccess = (userDetails) => ({
type: "GET_DETAILS",
userDetails,
});
export const checkLogin = (loginData, history) => {
const url = `login`;
return (dispatch) => {
return service
.post(url, loginData)
.then((res) => {
const userDetails = res.data.response_message;
dispatch(getUserDetailsSuccess(userDetails));
})
.catch((error) => {
throw error;
});
};
};
My Reducer code is
function loginReducer(state = { userDetails: {} }, action) {
switch (action.type) {
case "GET_DETAILS":
return { userDetails: action.userDetails };
default:
return state;
}
}
export default loginReducer;
My code is working fine without any issue.
Just add loginData into your dispatch
const getUserDetailsSuccess = (userDetails, loginData) => ({
type: "GET_DETAILS",
userDetails,
loginData
});
export const checkLogin = (loginData, history) => {
const url = `login`;
return (dispatch) => {
return service
.post(url, loginData)
.then((res) => {
const userDetails = res.data.response_message;
dispatch(getUserDetailsSuccess(userDetails, loginData));
})
.catch((error) => {
throw error;
});
};
};
and in the reducer action.loginData will be the content you want (don't sure how you want to store it)
function loginReducer(state = { userDetails: {} }, action) {
switch (action.type) {
case "GET_DETAILS":
return { userDetails: { ...action.userDetails, ...action.loginData } };
default:
return state;
}
}
export default loginReducer;

validation on signup if the user already exists in the database using react redux express

So, as the title suggests, I am trying to find if the user exists or not. Here's what I have done until now. I'm having trouble with handling validation in the handleSubmit function.
RegistrationForm.js
import React, { Component } from "react"
import { registerUser, checkValidUser } from "../actions/userActions"
import { connect } from "react-redux"
import validator from "validator"
import { Link } from "react-router-dom"
class RegistrationForm extends Component {
constructor(props) {
super(props)
this.state = {
username: "",
email: "",
password: "",
}
}
handleChange = (event) => {
const { name, value } = event.target
this.setState({
[name]: value,
})
}
handleSubmit = (event) => {
event.preventDefault()
const { username, email, password } = this.state
const registrationData = this.state
if (!username || !email || !password) {
return toastError("Credentials should not be empty")
}
if (username.length < 6) {
return toastError("Username should be greater than 6 characters.")
}
if (!validator.isEmail(email)) {
return toastError("Invalid email.")
}
if (password.length < 6) {
return toastError("Password must contain 6 characters.")
}
this.props.dispatch(checkValidUser(email)) // how do i properly handle validations here
this.props.dispatch(
registerUser(registrationData, () => this.props.history.push("/login"))
)
}
render() {
const isRegistrationInProgress = this.props.registration.isRegistrationInProgress
return (
<div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="username"
value={this.state.username}
className="input"
type="text"
placeholder="Username"
/>
<span className="icon is-small is-left">
<i className="fas fa-user"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input
onChange={this.handleChange}
name="email"
value={this.state.email}
className="input"
type="email"
placeholder="Email"
/>
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left">
<input
onChange={this.handleChange}
name="password"
value={this.state.password}
className="input"
type="password"
placeholder="Password"
/>
<span className="icon is-small is-left">
<i className="fas fa-lock"></i>
</span>
</p>
</div>
<div className="field">
<div className="control">
{isRegistrationInProgress ? (
<button className="button is-success is-loading">Sign Up</button>
) : (
<button onClick={this.handleSubmit} className="button is-success">
Sign up
</button>
)}
<Link to="/login">
<p className="has-text-danger">
Already have an account? Sign In
</p>
</Link>
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return state
}
export default connect(mapStateToProps)(RegistrationForm)
checkValidUser action creator
export const checkValidUser = (email) => {
return async dispatch => {
dispatch({ type: "CHECK_VALID_USER_STARTS" })
try {
const res = await axios.get(`${baseUrl}/users/checkValidUser/${email}`)
dispatch({
type: "CHECK_VALID_USER_SUCCESS",
data: { message: res.data.message }
})
} catch (err) {
dispatch({
type: "CHECK_VALID_USER_ERROR",
data: { error: "Something went wrong" },
})
}
}
}
route- router.get("/checkValidUser/:email", usersController.checkValidUser)
checkValidUser controller function
checkValidUser: async (req, res, next) => {
const { email } = req.params
try {
const user = await User.findOne({ email })
if (!user) {
return res.status(404).json({ error: "No user found" })
}
return res.status(200).json({ message: "User already exists" })
} catch (error) {
return next(error)
}
}
registration reducer
const initialState = {
isRegistrationInProgress: false,
isRegistered: false,
registrationError: null,
user: {},
message: "",
}
const registration = (state = initialState, action) => {
switch (action.type) {
case "REGISTRATION_STARTS":
return {
...state,
isRegistrationInProgress: true,
registrationError: null,
}
case "REGISTRATION_SUCCESS":
return {
...state,
isRegistrationInProgress: false,
registrationError: null,
isRegistered: true,
user: action.data,
}
case "REGISTRATION_ERROR":
return {
...state,
isRegistrationInProgress: false,
registrationError: action.data.error,
isRegistered: false,
user: {},
}
case "CHECK_VALID_USER_STARTS":
return {
...state,
isRegistrationInProgress: true,
}
case "CHECK_VALID_USER_SUCCESS":
return {
...state,
isRegistrationInProgress: false,
message: action.data.message,
}
case "CHECK_VALID_USER_ERROR":
return {
...state,
registrationError: action.data.error,
}
default:
return state
}
}
export default registration
Any help would be appreciated. Thanks.
Isn't checkValidUser the same type of validation like password.length < 6? I would just call it synchronously inside the validation. On the backend side I would change the status codes if possible. If the user already exists, it's the problematic case, so 419 (conflict) is a better fit than 200. 200 or 204 instead should be returned if the email wasn't used. With this the frontend check is quite easy:
export const checkValidUser = async (email) => {
try {
const res = await axios.get(`${baseUrl}/users/checkValidUser/${email}`)
return true
} catch (err) {
return false
}
}
and in handleSubmit
handleSubmit = async (event) => {
event.preventDefault()
const { username, email, password } = this.state
const registrationData = this.state
...
if(!(await checkValidUser(email))) {
return toastError("...")
}
this.props.dispatch(
registerUser(registrationData, () => this.props.history.push("/login"))
)
}
With this you don't need the CHECK_VALID_USER-states, but may want to add some kind of VALIDATION_IN_PROGRESS action to show some indicator on the page, that a background process is running, like a spinner. This can be achieved with a simple try/finally wrapper. So no matter in which case the validation will be exited the validation progress status will be reset.
handleSubmit = async (event) => {
event.preventDefault()
const { username, email, password } = this.state
const registrationData = this.state
try {
this.props.dispatch(setValidationProgress(true)
...
if(!(await checkValidUser(email))) {
return toastError("...")
}
} finally {
this.props.dispatch(setValidationProgress(false)
}
this.props.dispatch(
registerUser(registrationData, () => this.props.history.push("/login"))
)
}

Updating entries on Firebase (redux-react)

I am stuck around a project and honestly I don't know how to solve it (I am quite new before you judge)
so this is my code:
class EditProfile extends Component {
state = {
företagsnamn: '',
organisationsnummer: '',
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
handleSubmit = e => {
e.preventDefault();
// console.log(this.state);
this.props.editProfile(this.state);
this.props.history.push("/dash");
};
render() {
const { auth, profile } = this.props;
if (auth.isEmpty) return <Redirect to="/dash" />;
return (
<div >
<form className="white" onSubmit={this.handleSubmit}>
<div className="row">
<div className="col xl6 l6 m6 s12">
<label>Foretagsnamn:</label>
<input
type="text"
disabled
placeholder={profile.foretagsnamn}
id="foretagsnamn"
onChange={this.handleChange}
/>
</div>
<div className="col xl6 l6 m6 s12">
<label>organisationsnummer:</label>
<input
type="number"
placeholder={profile.organisationsnummer}
id="organisationsnummer"
onChange={this.onChange}
/>
</div>
</div>
<div className="input-field">
<button className="btn orange lighten-1" style={{width:'100%'}} >Submit</button>
{ }
</div>
</form>
</div>
}}
const mapStateToProps = state => {
return {
auth: state.firebase.auth,
profile: state.firebase.profile
};
};
const mapDispatchToProps = dispatch => {
return {
editProfile: profil => dispatch(editProfile(profil))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(EditProfile);
this was the action
export const editProfile = (profil) => {
return (dispatch, getState, { getFirestore, getFirebase }) => {
const firebase = getFirebase();
const firestore = getFirestore();
const profile = getState().firebase.auth
console.log(profile)
const authorId = getState().firebase.auth.uid;
// const foretagsnamn = getFirestore().firestore.collection('users').doc(profile.uid).foretagsnamn
// firebase.auth()
firestore.collection('users').doc(profile.uid).set({
// foretagsnamn: foretagsnamn,
// organisationsnummer: profil.organisationsnummer,
adress: profil.adress,
ort: profil.ort,
telefonnummer: profil.telefonnummer,
postnummer: profil.postnummer,
}, { merge: true }
).then(() => {
dispatch({ type: 'UPDATE_SUCCESS' });
}).catch(err => {
dispatch({ type: 'UPDATE_ERROR' }, err);
});
}}
and this the reducer
const editProfileReducer = (state = initState, action) => {
switch (action.type) {
case "EDITPROFILE_ERROR":
return {
...state,
editError: action.error
};
case "EDITPROFILE_SUCCESS":
return {
...state,
user:action.user
};
default:
return state;
}
}
export default editProfileReducer;
however when I press the button submit it shows this error:
FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: undefined
PS: Solved. The action was wrong. I changed ´´´const profile = getState().firebase.auth.```**instead of profile. **
Stays open if someone needs.

typeError: cannot read property 'users' of null in React

I'm trying to create a change password page in react and i'm getting typeError: cannot read property 'users' of null. The code works for other form pages(where i'm doing PUT and CREATE) but not this one
I tried binding the submit handler to the this keyword but that didn't work.
Also tried binding the handlePasswordChange to the this keyword
./formchange
import React from "react";
import { Link } from "react-router-dom";
var createReactClass = require("create-react-class");
var FormChange = createReactClass({
//setting initial state
getInitialState() {
return {
password: {}
};
},
handlePasswordChange(e) {
this.setState({
password: e.target.value
});
},
handleSubmit(e) {
e.preventDefault();
this.props.onSubmit(this.state);
this.props.history.push("/");
},
render() {
return (
<form
name="categories_post"
className="form-horizontal"
onSubmit={this.handleSubmit}
>
<div id="change_password">
<div className="form-group">
<label
className="col-sm-2 control-label required"
htmlFor="password"
>
Password
</label>
<div className="col-sm-10">
<input
type="text"
value={this.state.password}
onChange={this.handlePasswordChange}
id="password"
className="form-control"
/>
</div>
</div>
<button
type="submit"
id="formChangeSubmit"
className="btn btn-default"
>
Submit
</button>
</div>
</form>
);
}
});
export default FormChange;
./passwordupdate
import React from "react";
import { updateUsers, fetchUsers } from "./actions/appactions";
import FormChange from "./formchange";
var createReactClass = require("create-react-class");
const Update = createReactClass({
getIntitialState() {
return {
users: {}
};
},
componentWillReceiveProps(props) {
this.setState(props);
},
componentDidMount() {
fetchUsers(this.props.match.params.usersId)
.then(data => {
this.setState(state => {
state.users = data;
return state;
});
})
.catch(err => {
console.error("error", err);
});
},
handleSubmit(data) {
updateUsers(this.state.users.id, data);
},
render() {
return (
<div>
<FormChange
onSubmit={this.handleSubmit.bind}
password={this.state.users.password}
/>
</div>
);
}
});
export default Update;
//fetchusers function
export function fetchUsers(id) {
return fetch("https://localhost:44341/api/users/" + id, {
method: "GET",
mode: "cors"
})
.then(res => res.json())
.catch(err => err);
}
<FormChange
onSubmit={this.handleSubmit.bind(this)}
password={this.state.users.password}
/>
make this change and check
I'm not sure but you have data in handleSubmit as parameter but you don't pass it.
try this
You can call function like this:
handleSubmit=(data)=> {
updateUsers(this.state.users.id, data);
},
and call it
onSubmit={(data)=> this.handleSubmit(data)}
The problem was in ComponentDidMount(). The state was always null, had to change it to this
componentDidMount() {
fetchTheUsers(this.props.match.params.usersId)
.then(data => {
this.setState({
users: data
});
})
I did it that way initially because that's how it worked for my other update files. Hope this is useful to someone else.

Resources