React stateless functional components and component lifecycle

So I just switched to using stateless functional components in React with Redux and I was curious about the lifecycle of components. I originally had this:

// actions.js

export function fetchUser() {
    return {
        type: 'FETCH_USER_FULFILLED',
        payload: {
            name: 'username',
            career: 'Programmer'
        }
    }
}

      

Then in the component, I used the componentDidMount to retrieve the data like this:

// component.js

...
componentDidMount() {
  this.props.fetchUser()
}
...

      

After switching to stateless functional components, I now have a container with:

// statelessComponentContainer.js

...
const mapStateToProps = state => {
  return {
    user: fetchUser().payload
  }
}
...

      

As you can see, I am not currently fetching data asynchronously. So my question is, will this approach cause problems when I start fetching data asynchronously? And also is there a better approach?

I checked this blog where they say If your components need life methods, use ES6 classes . Any help would be appreciated.

+3


source to share


2 answers


First, don't do what you are trying to do in mapStateToProps

. Redux follows the unidirectional data flow pattern , in which the component dispatches an action that updates the state that changes the component. You shouldn't expect your action to return data, but rather expect the store to update with new data.

By following this approach, especially after you fetch data asynchronously, you will have to maintain a state in which your data has not yet been loaded. There are many questions and guides for this (even in another answer in this question) so I won't bother to give an example here for you.

Second, it is a common use case to want to receive data asynchronously when the component is mounted. The desire to write a good functional component is a common desire. Luckily, I have a library that allows you to do: react-redux-lifecycle .

Now you can write:



import { onComponentDidMount } from 'react-redux-lifecycle'
import { fetchUser } from './actions'

const User = ({ user }) => {
   return // ...
}

cont mapStateToProps = (state) => ({
  user = state.user
})

export default connect(mapStateToProps)(onComponentDidMount(fetchUser)(User))

      

I've made some assumptions about your component names and storage structure, but I hope that's enough to get the idea. I'm glad to clarify something for you.

Disclaimer: I am the author of the recct-lifecycle library.

+2


source


Do not display any view if no data is available yet. This is how you do it.

The approach to solving your problem is to return promise

from this.props.fetchUser()

. You need dispatch

your action using react-thunk (see examples and information on how to set it up. It's easy!).

The action fetchUser

should look like this:

export function fetchUser() {
  return (dispatch, getState) => {
      return new Promise(resolve => {
          resolve(dispatch({         
          type: 'FETCH_USER_FULFILLED',
          payload: {
            name: 'username',
            career: 'Programmer'
          }
        }))
      });
  };
}

      

Then, in your method, Component

add the componentWillMount()

following code to the lifecycle :



componentDidMount() {
  this.props.fetchUser()
    .then(() => {
      this.setState({ isLoading: false });
    })
}

      

Of course, your class constructor

must have an initial state isLoading

set to true

.

constructor(props) {
  super(props);

  // ...

  this.state({
    isLoading: true
  })
}

      

Finally, in your method, render()

add a condition. If your request is still pending and we have no data, the print "data is still loading ..." otherwise shows <UserProfile />

"Component".

render() {
  const { isLoading } = this.state;

  return (
    <div>{ !isLoading ? <UserProfile /> : 'data is still loading...' }</div>
  )
}

      

+1


source







All Articles