Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
July 13, 2021 06:24 am GMT

Managing React State with Zustand

Managing React State with Zustand

Managing React State with Zustand

A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy api based on hooks, isn't boilerplatey or opinionated.

  • Zustand - https://zustand.surge.sh/ - Means condition or state in German - definition of zustand

  • global state is all of the objects that are needed through out the application

  • There are various state management packages available for react, the most common would probably be react-redux. We are looking for a more straight forward state management library that doesn't require a lot of boiler-plate

    Blog Post on different State Management Libraries - React State Management Libraries and How to Choose

  • Apps have local state which are local to the specific component, this can be managed with useState

  • I think that zustand is simple enough to pick up and use without requiring a lot of deep understanding of state management concepts and it just works... It is exactly what will work in place of react-redux

Simple list of students that can be created, updated or delete

  • Create the store and then add the necessary functions
// store/index.jsimport create from 'zustand';const useStore = create(set => ({  students: [    { id: '1', name: 'Aaron Saunders', section: 'advanced' },    { id: '2', name: 'Andrea Saunders', section: 'beginners' },    { id: '3', name: 'Bill Smith', section: 'beginners' },    { id: '4', name: 'John Chambers', section: 'beginners' },    { id: '5', name: 'Joe Johnson', section: 'advanced' }  ]}));export const useStudentStore = useStore;
  • a function to add
  addStudent: student =>    set(state => ({      students: [        {          name: student.name,          id: Math.random() * 100 + '',          section: student.section        },        ...state.students      ]    })),
  • a function to update
updateStudent: student =>    set(state => ({      students: state.students.map(item => {        if (item.id === student.id) {          return {            ...item,            name: student.name,            section: student.section          };        } else {          return item;        }      })    }))
  • a function to delete
  removeStudent: id =>    set(state => ({      students: state.students.filter(student => student.id !== id)    })),
  • a way to get all of the students, since the students are a property on the store we can access it directly
 const students = useStudentStore(state => state.students);
  • a way to get an individual student, since students are on the store we can access the students directly and filter based on id. We can also cache or memoize the value with react's useCallback hook and reuse the result as long as the student id doesn't change
  const student = useStudentStore(    useCallback(state => state.students.find(s => s.id === studentId), [      studentId    ])  );

Accessing The Store

// import it in the componentimport { useStudentStore } from '../store';// use it in the function, get all the studentsconst students = useStudentStore(state => state.students);// get the function from the store to add studentsconst addStudent = useStudentStore(state => state.addStudent);

Full App Example

https://stackblitz.com/edit/react-managing-state-with-zustand?file=src/pages/Detail.jsx

create a blank app with ionic

ionic start --type=react

install zustand - https://zustand.surge.sh/

npm install zustand
// store/index.jsimport create from 'zustand';import { devtools, persist } from 'zustand/middleware';const useStore = create(set => ({  students: [    { id: '1', name: 'Aaron Saunders', section: 'advanced' },    { id: '2', name: 'Andrea Saunders', section: 'beginners' },    { id: '3', name: 'Bill Smith', section: 'beginners' },    { id: '4', name: 'John Chambers', section: 'beginners' },    { id: '5', name: 'Joe Johnson', section: 'advanced' }  ],  addStudent: student =>    set(state => ({      students: [        {          name: student.name,          id: Math.random() * 100 + '',          section: student.section        },        ...state.students      ]    })),  removeStudent: id =>    set(state => ({      currentStudent: state.students.filter(student => student.id !== id)    })),  updateStudent: student =>    set(state => ({      students: state.students.map(item => {        if (item.id === student.id) {          return {            ...item,            name: student.name,            section: student.section          };        } else {          return item;        }      })    }))}));export const useStudentStore = useStore;
// Home.jsximport {  IonButton,  IonButtons,  IonContent,  IonHeader,  IonIcon,  IonItem,  IonLabel,  IonList,  IonModal,  IonPage,  IonTitle,  IonToolbar} from '@ionic/react';import { trashOutline, pencilOutline } from 'ionicons/icons';import { useStudentStore } from '../store';import AddStudentModal from '../components/AddStudentModal';import React, { useState } from 'react';import { useHistory } from 'react-router';const Home = () => {  const history = useHistory();  const [modalOpen, setModalOpen] = useState(false);  const [modalData, setModalData] = useState(null);  const students = useStudentStore(state => state.students);  const addStudent = useStudentStore(state => state.addStudent);  const removeStudent = useStudentStore(state => state.removeStudent);  const updateStudent = useStudentStore(state => state.updateStudent);  console.log(students);  /**   *   * @param response   */  const handleModalClose = response => {    setModalOpen(false);    if (response) {      console.log(response);      if (response.id) {        updateStudent({          name: response.name,          section: response.section,          id: response.id        });      } else {        addStudent({ name: response.name, section: response.section });      }    }    modalData && setModalData(null);  };  const handleDelete = id => {    removeStudent(id);  };  const editItem = item => {    setModalData(item);    setModalOpen(true);  };  return (    <IonPage>      <IonHeader>        <IonToolbar>          <IonTitle>Student Manager</IonTitle>          <IonButtons slot="end">            <IonButton onClick={() => setModalOpen(true)}>ADD</IonButton>          </IonButtons>        </IonToolbar>      </IonHeader>      <IonContent fullscreen>        {/* <!-- modal --> */}        <IonModal isOpen={modalOpen}>          <AddStudentModal            onCloseModal={handleModalClose}            initialData={modalData}          />        </IonModal>        {/* <!-- list --> */}        <IonList>          {students.map(item => (            <IonItem key={item.id}>              <IonLabel onClick={() => history.push(`/detail/${item.id}`)}>                <h1>{item.section}</h1>                {item.name}              </IonLabel>              <IonButton                onClick={() => handleDelete(item.id)}                fill="outline"                color="danger"              >                <IonIcon color="danger" icon={trashOutline} />              </IonButton>              <IonButton onClick={() => editItem(item)} fill="outline">                <IonIcon icon={pencilOutline} />              </IonButton>            </IonItem>          ))}        </IonList>      </IonContent>    </IonPage>  );};export default React.memo(Home);
// Detail.jsximport {  IonButton,  IonBackButton,  IonButtons,  IonContent,  IonHeader,  IonIcon,  IonItem,  IonLabel,  IonList,  IonModal,  IonPage,  IonTitle,  IonToolbar} from '@ionic/react';import { useStudentStore } from '../store';import AddStudentModal from '../components/AddStudentModal';import React, { useState, useEffect, useCallback } from 'react';import { useParams } from 'react-router';import { useStudentStore } from '../store';const Detail = () => {  const { studentId } = useParams();  const student = useStudentStore(    useCallback(state => state.students.find(s => s.id === studentId), [      studentId    ])  );  return (    <IonPage>      <IonHeader>        <IonToolbar>          <IonTitle>Student Manager</IonTitle>          <IonButtons slot="start">            <IonBackButton />          </IonButtons>        </IonToolbar>      </IonHeader>      <IonContent fullscreen className="ion-padding">        <p>{student && JSON.stringify(student)}</p>      </IonContent>    </IonPage>  );};export default React.memo(Detail);

Using the state information from above to create an input form to capture the data on the students when they need to be added and removed from the list

// AddStudentModal.jsximport {  IonButton,  IonContent,  IonHeader,  IonInput,  IonItem,  IonLabel,  IonPage,  IonSelect,  IonSelectOption,  IonToolbar} from '@ionic/react';import React, { useState, useEffect } from 'react';const AddStudentModal = ({ onCloseModal, initialData }) => {  const [section, setSection] = useState();  const [name, setName] = useState();  useEffect(() => {    setSection(initialData?.section);    setName(initialData?.name);  }, []);  const handleCancel = () => {    onCloseModal(null);  };  const handleSave = () => {    onCloseModal({      name,      section,      id: initialData?.id    });  };  return (    <IonPage>      <IonHeader>        <IonToolbar />      </IonHeader>      <IonContent className="ion-padding">        <strong>Ready to create an app?</strong>        <IonItem>          <IonLabel>Name</IonLabel>          <IonInput value={name} onIonChange={e => setName(e.detail.value)} />        </IonItem>        <IonItem>          <IonLabel>Section</IonLabel>          <IonSelect            value={section}            placeholder="Select One"            onIonChange={e => setSection(e.detail.value)}          >            <IonSelectOption value="advanced">Advanced</IonSelectOption>            <IonSelectOption value="beginners">Beginners</IonSelectOption>          </IonSelect>        </IonItem>        <div style={{ paddingTop: 10 }}>          <IonButton onClick={handleSave}>SAVE STUDENT</IonButton>          <IonButton onClick={handleCancel} color="danger">            CANCEL          </IonButton>        </div>      </IonContent>    </IonPage>  );};export default AddStudentModal;
// App.jsximport React, { useState } from 'react';import { IonApp, IonContent, IonPage, IonRouterOutlet } from '@ionic/react';import { IonReactRouter } from '@ionic/react-router';import { Route, Link, Redirect } from 'react-router-dom';/* Core CSS required for Ionic components to work properly */import '@ionic/react/css/core.css';/* Basic CSS for apps built with Ionic */import '@ionic/react/css/normalize.css';import '@ionic/react/css/structure.css';import '@ionic/react/css/typography.css';/* Optional CSS utils that can be commented out */import '@ionic/react/css/padding.css';import '@ionic/react/css/float-elements.css';import '@ionic/react/css/text-alignment.css';import '@ionic/react/css/text-transformation.css';import '@ionic/react/css/flex-utils.css';import '@ionic/react/css/display.css';import './styles.css';import Home from './pages/Home';import Detail from './pages/Detail';function App() {  return (    <IonApp>      <IonReactRouter>        <IonRouterOutlet>          <Route exact path="/home" component={Home} />          <Route exact path="/detail/:studentId" component={Detail} />          <Route exact path="/">            <Redirect to="/home" />          </Route>        </IonRouterOutlet>      </IonReactRouter>    </IonApp>  );}export default App;
// index.tsximport React from 'react';import ReactDOM from 'react-dom';import App from './App';import * as serviceWorkerRegistration from './serviceWorkerRegistration';import reportWebVitals from './reportWebVitals';ReactDOM.render(  <React.StrictMode>    <App />  </React.StrictMode>,  document.getElementById('root'));// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://cra.link/PWAserviceWorkerRegistration.unregister();// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();

Video


Original Link: https://dev.to/aaronksaunders/managing-react-state-with-zustand-2e8k

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To