0

I'm creating a React application with Redux, and on my Account Settings page I have a form that I want pre-populated with the user's info and then give them the ability to edit the fields and update their profile. My code is as follows:

class UpdateProfile extends Component {
  constructor(props) {
    super(props);
    this.props.getCurrentProfile();
    this.state = {
      firstName: "",
      lastName: "",
      email: "",
      gender: "",
      bday: "",
      address1: "",
      address2: "",
      zipCode: "",
      phone: "",
      contactMethod: "",
      plan: "",
      apptReminders: true,
      updates: true,
      errors: {}
    };

    // Bind functions
    this.onChange = this.onChange.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
  }

  // static getDerivedStateFromProps(nextProps) {
  //   if (nextProps.profile) {
  //     let personal = nextProps.profile.profile.personalInfo;
  //     let account = nextProps.profile.profile.accountInfo;
  //     return {
  //       firstName: personal.firstName,
  //       lastName: personal.lastName,
  //       email: personal.email,
  //       address1: personal.address1,
  //       address2: personal.address2,
  //       zipCode: personal.zipCode,
  //       phone: personal.phone,
  //       contactMethod: account.contactMethod,
  //       plan: account.plan,
  //       apptReminders: account.alerts.apptReminders,
  //       updates: account.alerts.updates
  //     };
  //   } else {
  //     return null;
  //   }
  // }

  componentWillReceiveProps(nextProps) {
    if (nextProps) {
      let personal = nextProps.profile.profile.personalInfo;
      let account = nextProps.profile.profile.accountInfo;
      this.setState({
        firstName: personal.firstName,
        lastName: personal.lastName,
        email: personal.email,
        address1: personal.address1,
        address2: personal.address2,
        zipCode: personal.zipCode,
        phone: personal.phone,
        contactMethod: account.contactMethod,
        plan: account.plan,
        apptReminders: account.alerts.apptReminders,
        updates: account.alerts.updates
      });
    }
  }

this.props.getCurrentProfile() sends an axios request to mongoDB and receives the profile of the current user.

The issue is that if I use the getDerivedStateFromProps method, the text fields are static and cannot be edited. And even using the componentWillMount method, I get an error if I refresh the page from the browser saying the profile is null.

I am very new to React and the lifecycle methods and would greatly appreciate any feedback on what I'm doing incorrectly and also why componentWillReceiveProps is being deprecated.

Thanks in advance

Adam Johnston
  • 1,399
  • 2
  • 12
  • 23

2 Answers2

0

Well after some more reading on lifecycle methods I came up with this solution:

 // Get profile
  componentDidMount() {
    this.props.getCurrentProfile();
  }

  // Fill in form
  componentDidUpdate(prevProps) {
    if (
      this.props.profile.profile &&
      prevProps.profile.profile !== this.props.profile.profile
    ) {
      let personal = this.props.profile.profile.personalInfo;
      let account = this.props.profile.profile.accountInfo;
      this.setState({
        firstName: personal.firstName,
        lastName: personal.lastName,
        email: personal.email,
        address1: personal.address1,
        address2: personal.address2,
        zipCode: personal.zipCode,
        phone: personal.phone,
        contactMethod: account.contactMethod,
        plan: account.plan
      });
    }
  }

This works as needed, although it renders twice. If anyone knows of a way to wait until the request comes back to render I would appreciate it. FYI I'm using Redux

Adam Johnston
  • 1,399
  • 2
  • 12
  • 23
0

I don't see where you are using redux in this application.Redux store should be a single source of truth and you shouldn't be using local state for managing your accounts.

Also, redux is not meant for asynchronous actions, axios is aysnchronous and you need to use a middleware like thunk so your actions can return a function instead of just a type. Then you can call dispatch from the returned async call that will update your store.

I would recommend starting: https://redux.js.org/introduction and then advance to async actions: https://redux.js.org/advanced/async-actions.

This tutorial made the most sense to me when I started: https://codepen.io/stowball/post/a-dummy-s-guide-to-redux-and-thunk-in-react

//Example of asyn call in redux with thunk      
function fetchPosts(subreddit){
      //Thunk middleware knows how to handle functions.
      //It passes the dispatch method as an argument to the function,
      //thus making it able to dispatch actions itself.

    return dispatch =>{
            dispatch(requestPosts(subreddit))        
        return axios.get(`https://www.reddit.com/r/${subreddit}.json`,{headers: { 'Content-Type': 'text/plain;charset=utf-8'}})
        .then( res =>{                 
            dispatch(receivePosts(subreddit,res.data))
        }).catch(error=>{
            console.log(error);
        })
    }
  }
Sir Codes Alot
  • 1,149
  • 8
  • 11
  • I'm using redux in separate modules. this.getCurrentProfile() calls an action that sends an axios request. I'm using thunk in that action module. The state shown above is only managing the state of the form and has no affect on the store. On submit the state of the form is then formatted to fit the mongoose schema and sent to my DB – Adam Johnston Jul 11 '18 at 22:17