Maîtrisez React

Découvrez React et son écosystème, quel que soit votre niveau.

Enregistrer un state local dans le local storage du navigateur

October 28, 2018

Lorsqu’on développe un projet avec React, il est fréquent de se concentrer d’abord sur l’expérience utilisateur (donc principalement les composants), alors que le back-end n’est pas encore prêt (une autre équipe s’en occupe, ou bien on le fait dans un second temps).

Mais on souhaite tout de même conserver les éléments créés par l’utilisateur, ne serait-ce que parce que pour tester ses composants dans le navigateur, on en a rapidement assez de refaire systématiquement les mêmes manipulations (par exemple pour une liste de tâches, créer plusieurs tâches pour tester la suppression…).

Voici une petite astuce très simple qui vous permettra de sauvegarder les données de votre application dans le local storage de votre navigateur. Cela ne fonctionnera qu’à la condition que l’état de l’application ne soit stocké que dans le state local d’un seul composant. Mais avec un peu d’adaptation vous pourrez gérer facilement d’autres cas.

Attention : il s’agit d’une astuce à utiliser pendant le développement uniquement ! Cette manière de persister des données n’est pas efficace et ne fonctionnera pas sur certains navigateurs.

Pour écrire dans le local storage du navigateur on utilisera localStorage.setItem, et pour lire localStoage.getItem. L’astuce consiste donc simplement à utiliser ces méthodes au chargement du composant principal de l’application et lorsque l’état est mis à jour.

Prenons un exemple simple d’un composant de gestion de tâches :

class App extends Component {
  state = { tasks: [] }
  addTask = () => {
    this.setState({ tasks: [...this.state.tasks, 'New task'] })
  }
  render() {
    return (
      <div>
        <button onClick={this.addTask}>New</button>
        <ul>
          {this.state.tasks.map(task => (
            <li>{task}</li>
          ))}
        </ul>
      </div>
    )
  }
}

Tout d’abord on créera une méthode saveStateToLocalStorage qui comme son nom l’indique sauvegardera le state du composant dans le local storage :

saveStateToLocalStorage = () => {
  localStorage.setItem('state', JSON.stringify(this.state))
}

Notez que le local storage ne peut contenir que des chaînes de caractères, on passe donc par une sérialisation en JSON.

Ensuite, on appellera cette méthode à chaque mise à jour du state. Pour cela on la passera en second paramètre de setState, nous assurant ainsi que le state a bien été mis à jour avant de le sauvegarder :

addTask = () => {
  this.setState(
    { tasks: [...this.state.tasks, 'New task'] },
    this.saveStateToLocalStorage
  )
}

Enfin, pour récupérer notre state au chargement du composant, on récupèrera la valeur stockée dans le local storage que l’on désérialisera pour appeler setState, le tout dans componentWillMount :

componentDidMount() {
  const state = localStorage.getItem('state')
  if (state) {
    this.setState(JSON.parse(state))
  }
}

Et voilà ! Simple non ?

Encore une fois : il ne s’agit pas d’une technique à mettre en place en production, elle comporte de nombreux défauts (le fait de devoir sérialiser les données sans vérification des références circulaires par exemple). Mais elle est néanmoins très pratique pendant la phase de développement, il serait donc dommage de s’en priver ;)