ReactJS + Redux Edit form - reactjs

I have the following form:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { updateExpert, fetchExpert } from "../../store/actions/expertActions";
class ExpertForm extends Component {
state = {
expert: {}
};
componentWillMount() {
console.log("ComponentWillMount");
const id = this.props.match.params.id;
console.log("Will fetch expert with id", id);
this.props.fetchExpert(id);
}
handleChange = e => {
console.log(e);
this.setState({
expert: {
...this.state.expert,
[e.target.id]: e.target.value
}
});
};
componentWillReceiveProps(nextProps) {
const newExpert = nextProps.expert;
console.log("got new expert ", newExpert);
this.setState({
expert: nextProps.expert
});
}
handleSubmit = e => {
e.preventDefault();
const originalExpert = this.props.expert;
console.log("Expert before", originalExpert);
// const updatedExpert = {
// firstName: this.state.expert.firstName,
// lastName: this.state.expert.lastName,
// bio: this.state.expert.bio,
// country: originalExpert.country,
// interestIds: originalExpert.interestIds,
// city: originalExpert.city,
// summary: originalExpert.summary,
// websiteText: originalExpert.websiteText,
// websiteUrl: originalExpert.websiteUrl
// };
const updatedExpert = this.state.expert;
console.log("Expert after", updatedExpert);
//call action
this.props.updateExpert(originalExpert.userId, updatedExpert);
};
render() {
const { expert } = this.props;
return (
<div className="container">
<div className="card">
<form onSubmit={this.handleSubmit} className="white">
<div className="card-content">
<h5 className="grey-text text-darken-3">Update expert</h5>
<div className="row">
<div className="input-field col s6">
<label htmlFor="firstName">First Name</label>
<input
onChange={this.handleChange}
type="text"
id="firstName"
/>
</div>
<div className="input-field col s6">
<label htmlFor="lastName">Last Name</label>
<input
onChange={this.handleChange}
type="text"
id="lastName"
/>
</div>
</div>
<div className="input-field">
<label htmlFor="bio">Bio</label>
<textarea
className="materialize-textarea"
id="bio"
onChange={this.handleChange}
/>
</div>
<div className="input-field">
<label htmlFor="summary">Summary</label>
<textarea
className="materialize-textarea"
id="summary"
onChange={this.handleChange}
/>
</div>
<div className="row">
<div className="input-field col s6">
<label htmlFor="country">Country</label>
<textarea
className="materialize-textarea"
id="country"
onChange={this.handleChange}
/>
</div>
<div className="input-field col s6">
<label htmlFor="city">City</label>
<textarea
className="materialize-textarea"
id="city"
onChange={this.handleChange}
/>
</div>
</div>
<div className="row">
<div className="input-field col s6">
<label htmlFor="websiteText">Website text</label>
<textarea
className="materialize-textarea"
id="websiteText"
onChange={this.handleChange}
/>
</div>
<div className="input-field col s6">
<label htmlFor="websiteUrl">Website URL</label>
<textarea
className="materialize-textarea"
id="websiteUrl"
onChange={this.handleChange}
/>
</div>
</div>
</div>
<div className="card-action">
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Update</button>
</div>
</div>
</form>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
expert: state.experts.item
});
const mapDispatchToProps = dispatch => {
return {
updateExpert: (id, expert) => dispatch(updateExpert(id, expert)),
fetchExpert: id => dispatch(fetchExpert(id))
};
};
export default connect(
mapStateToProps, //mapstatetoprops
mapDispatchToProps //mapdispatchtoprops
)(ExpertForm);
Now this form is used mostly to edit an item of the Expert type, not adding it. Which means I should prefill it with the information already stored in the database.
However when I try to set the value directly on an input like so:
<input
value={expert.firstName}
onChange={this.handleChange}
type="text"
id="firstName"
/>
I get the following error:
index.js:1452 Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
This is the ExpertList component from which the user accesses this ExpertForm:
import React, { Component } from "react";
import PropTypes from "prop-types";
import ExpertItem from "./expert-item";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { fetchExperts } from "../../store/actions/expertActions";
class ExpertList extends Component {
componentWillMount() {
console.log("ComponentWillMount");
this.props.fetchExperts();
}
componentWillReceiveProps(nextProps) {
console.log("Rceived new props");
}
render() {
const { experts } = this.props;
const expertsDom = experts.map(expert => (
<Link to={"/expert/edit/" + expert.userId}>
<ExpertItem key={expert.userId} expert={expert} />
</Link>
));
return <div className="expert-list section">{expertsDom}</div>;
}
}
const mapStateToProps = state => ({
experts: state.experts.items
});
export default connect(
mapStateToProps,
{ fetchExperts }
)(ExpertList);
These are my actions :
import {
FETCH_EXPERTS,
UPDATE_EXPERT,
ADD_EXPERT,
FETCH_EXPERT
} from "./types";
import axios from "../../network/axios";
export const createExpert = expert => {
return (dispatch, getState) => {
//make async call to database
dispatch({ type: ADD_EXPERT, expert: expert });
// type: ADD_EXPERT;
};
};
export const fetchExpert = id => {
return (dispatch, getState) => {
console.log("fetching expert with id ", id);
axios
.get("/connections/experts")
.then(response => {
const selectedExpert = response.data.filter(e => {
return e.userId === id;
})[0];
console.log("ExpertsData ", selectedExpert);
// const newState = Object.assign({}, this.state, {
// experts: newExperts
// });
dispatch({
type: FETCH_EXPERT,
payload: selectedExpert
});
})
.catch(error => {
console.log(error);
});
};
};
//Thunk allows us to call dispatch directly so that we can make async requests
//We can consider dispatch a resolver/promise, calling dispatch is just sending
//the data back
export const fetchExperts = () => {
return (dispatch, getState) => {
console.log("fetching");
console.log("getstate ", getState());
const accessToken = getState().auth.authInfo.accessToken;
console.log("authToken ", accessToken);
axios
.get("/connections/experts")
.then(response => {
const newExperts = response.data;
console.log("ExpertsData ", newExperts);
// const newState = Object.assign({}, this.state, {
// experts: newExperts
// });
dispatch({
type: FETCH_EXPERTS,
payload: newExperts
});
})
.catch(error => {
console.log(error);
});
};
};
export const updateExpert = (id, expertData) => {
return dispatch => {
console.log("updating expert", id, expertData);
axios
.put("/experts/" + id, expertData)
.then(response => {
const updatedExpert = response.data;
dispatch({
type: UPDATE_EXPERT,
payload: updatedExpert
});
})
.catch(error => {
console.log(error);
});
};
};
And this is my reducer:
import {
FETCH_EXPERTS,
UPDATE_EXPERT,
FETCH_EXPERT
} from "../../store/actions/types";
const initialState = {
items: [],
item: {}
};
const expertReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_EXPERT:
console.log("reducer fetch by id");
return {
...state,
item: action.payload
};
case FETCH_EXPERTS:
console.log("reducer fetch");
return {
...state,
items: action.payload
};
case UPDATE_EXPERT:
console.log("reducer update");
return {
...state,
item: action.payload
};
default:
return state;
}
};
export default expertReducer;

Instead of using value property, You need to use defaultValue as described here in Default Values section if You want to have a default value for input field.

The problem is that your value is undefined before Redux's state is loaded. You can solve this by giving it an empty string by default, something like this:
<input
value={typeof expert.firstName === 'undefined' ? '' : expert.firstName}
onChange={this.handleChange}
type="text"
id="firstName"
/>

Related

how to fix issues with react datepicker

Below are 2 files that is expected to display details in a form, name, service, date, cost. The problem is that it doesn't display information entered in other input fields when I choose a future date. Whereas when I use the current date, it displays the information entered in other input fields as expected. Why is this the case please and how do i fix it?
import { useState, useEffect } from 'react';
import axios from 'axios';
const ConfirmBooking = () => {
//track state
const [data,setData] = useState([])
const Style = {
color: 'rgb(97, 113, 154)',
padding: '5px'
}
//GET data
useEffect(() => {
axios
.get('http://localhost:5000/api/bookings')
.then(res => {
console.log(res)
setData(res.data)
})
.catch(err => {
console.log(err)
})
}, [])
//DELETE data
const deleteHandler =(id) =>{
axios
.delete('http://localhost:5000/api/bookings/'+id)
.then(res => {
console.log(res.data);
}
)
.catch(error =>{
console.log(error)
})
}
if(!data?.length) return <div>loading...</div>
return (
<div className='bookings'>
<h4 style={Style}>Name:{" "}{data.at(-1).name}</h4>
<h4 style={Style} >Service:{" "}{data.at(-1).service}</h4>
<h4 style={Style} >Date:{" "}{data.at(-1).date}</h4>
<h4 style={Style} >Cost:{" "}{data.at(-1).cost}</h4><br></br>
<button className='Btn'>Edit</button>
<button className='Btn' onClick={ () => deleteHandler(data.at(-1))} >Delete</button>
</div>
)
}
export default ConfirmBooking;
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom'
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
const Form = () => {
const navigate = useNavigate();
const [myState, setMyState] = useState({
name: "",
service: "finance",
date: new Date(),
cost: "3$"
});
//event to handle all inputs except datepicker
const handleChange = (e)=> {
// const { name, value} = e.target;
const name = e.target.name;
const value = e.target.value
//to update the input myState
setMyState
({...myState, [name]: value });
}
const handleDateChange = (date) => {
setMyState({
date:date
})
}
const handleSubmit = (e) => {
e.preventDefault();
if (myState !== "") {
alert('booking success')
}
//Add data to database
axios.post('http://localhost:5000/api/bookings', myState)
.then(res => {
setMyState
(res.data);
console.log(res);
//redirect to another page
navigate('/ConfirmBooking')
})
.catch((error) => {
console.log(error)
})
}
return (
<form className='form' onSubmit={handleSubmit} >
<h2 className="headerForm">Create appointment</h2>
<div className="mb-3">
<label className="form-label">Name</label>
<input name='name' type="text" className="form-control" id="exampleFormControlInput1" value={myState.name} onChange={handleChange} />
<label className="form-label">Service</label>
<input name='service' type="text" className="form-control " id="exampleFormControlInput1" value={myState.service} onChange={handleChange} />
<label className="form-label"> Date</label>
<div>
<DatePicker
selected={myState.date}
onChange={handleDateChange}
startDate = {new Date()}
minDate={new Date()}
filterDate={date => date.getDay() !== 6 && date.getDay() !== 0}
/>
</div>
<label className="form-label">Cost</label>
<input name='cost' type="text" className="form-control" id="exampleFormControlInput1" value={myState.cost} onChange={handleChange} />
</div>
<button >Submit</button>
</form>
)
}
export default Form;
This method is changing the state without other properties:
...
const handleDateChange = (date) => {
setMyState({
date:date
})
}
...
If you want to change this property from state, you need to destructure previous value and change date.
const handleDateChange = (date) => {
setMyState({
...myState,
date:date
})
}

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})
})
}
};

Updating object's state in redux

What is the best way to update an objects state in redux using one function for multiple inputs?
I have 3 inputs - if possible, I'd like to update corresponding input field to redux object field using one function... or best practice.
// Contact.js
this.state = {
contactInfo: {
firstName: '',
address: '',
city: '',
}
}
onChangeInfo = (event, action) => {
const { dispatch } = this.props;
const { contactInfo } = this.state;
// Is this an issue?
contactInfo[event.target.name] = event.target.value;
if (action === 'CHANGE') {
dispatch(updateContactInfo(contactInfo));
this.setState({ contactInfo });
} else {
this.setState({ contactInfo });
}
}
render() {
const { firstName, address, city } = this.state.contactInfo;
return (
<div>
<div>
<input placeholder=" " type="text" name='firstName' value={firstName} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>First & last name</span></div>
</div>
<div>
<input placeholder=" " type="text" name="address" value={address} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>Address</span></div>
</div>
<div>
<input placeholder=" " type="text" name="city" value={city} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>City</span></div>
</div>
</div>
)}
// Reducer
const initialState = {
contactInformation: [],
}
export default function (state, action) {
state = state === undefined ? initialState : state;
switch (action.type) {
case 'CONTACT_INFO': {
state.contactInformation.test.info = payload;
return Object.assign({}, state, action.payload);
}
default: return state;
}
}
I don't see the point of using setState in this case
this.state = {
contactInfo: {...this.props}
}
onChangeInfo = ({target: {name, value}}, action) => {
const { dispatch } = this.props;
const contactInfo = {[name]: value};
if (action === 'CHANGE') {
dispatch(updateContactInfo(contactInfo));
}
}
Example
const { Component, useState, useEffect } = React;
const { bindActionCreators, combineReducers, createStore, applyMiddleware, compose } = Redux;
const { connect, Provider } = ReactRedux;
const initalState = {
contactInfo: {
firstName: '',
address: '',
city: ''
}
}
const reducer = (state = initalState, action) => {
switch (action.type) {
case 'CONTACT_INFO': {
const newState = {
...state,
contactInfo: {
...state.contactInfo,
...action.payload.contactInfo
}
};
return newState;
}
default: return state;
}
}
const reducers = combineReducers({
reducer
})
const store = createStore(
reducers
);
const updateContactInfo = (payload) => ({
type: 'CONTACT_INFO', payload
})
const mapStateToProps = state => {
return {
contactInfo: state.reducer.contactInfo
}
}
const mapDispatchToProps = dispatch => ({
updateContactInfo: payload => dispatch(updateContactInfo(payload))
})
class _App extends Component {
constructor(props) {
super(props);
this.state = {...this.props}
this.updateContactInfo = this.props.updateContactInfo;
}
static getDerivedStateFromProps (props, state) {
return {...props}
}
onChangeInfo ({target: {name, value}}, action) {
const contactInfo = { contactInfo: {[name]: value}};
if (action === 'CHANGE') {
this.updateContactInfo(contactInfo);
}
}
render() {
const { firstName, address, city } = this.state.contactInfo;
return <div>
<div>
<input placeholder=" " type="text" name='firstName' value={firstName} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>First & last name</span></div>
</div>
<div>
<input placeholder=" " type="text" name="address" value={address} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>Address</span></div>
</div>
<div>
<input placeholder=" " type="text" name="city" value={city} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>City</span></div>
</div>
{JSON.stringify(this.state)}
</div>
}
}
const App = connect(mapStateToProps, mapDispatchToProps)(_App)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.10.1/polyfill.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/redux#4.0.5/dist/redux.js"></script>
<script src="https://unpkg.com/react-redux#latest/dist/react-redux.js"></script>
<div id="root"></div>
I would suggest you to maintain three different actions as best practise
as an action is always a pure function and specific to one particular operation.
export const firstName = (firstName) => ({
type : 'FIRST_NAME',
payload : firstName
});
export const address = (address) => ({
type : 'ADDRESS',
payload : address
});
export const city = (city) => ({
type : 'CITY',
payload : city
});
And, in the reducer, update the store based on action.type
Great question.
There are a few things I have to point out before I give you an answer. There is generally 2 types of state that exists in any application: long lived state and short lived (a.k.a ephemeral) state. Redux is meant to serve you as a container to place all your long term states that is of general concern to potentially different parts of your application.
With that said, I can see that the only thing you are doing in your app is updating the state with the user input. I bet you then use that state to do something when the user clicks a submit button. If that is your case, the inputs by definition are ephemeral and I would NOT place the input states in Redux at all. Instead, I'd only fire 1 action when the user submits the form.
<form onSubmit={onSubmitHandler}>
<input name="name" type="text" />
<input name="hobby" type="text" />
<button type="submit" />
<form />
------
// this is slight pseudo-code, but hopefully you get the gist
const onSubmitHandler = (event) => {
const myFields = // get fields from event object.
dispatch({type: 'SOME-ACTION', fields: myFields})
}
I'd also advise you to consider changing how you are generally modelling your actions. You can watch this video that goes over what I mean.

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;

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.

Resources