Skip to content

React API

useAtom(atom, store)

Hook to use an atom in a React component.

Basic Usage

javascript
import { atom, createStore } from '@nexus-state/core';
import { useAtom } from '@nexus-state/react';

const countAtom = atom(0, 'counter');
const store = createStore();

function Counter() {
  const [count, setCount] = useAtom(countAtom, store);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
}

Computed Atoms

javascript
const firstNameAtom = atom('John', 'firstName');
const lastNameAtom = atom('Doe', 'lastName');

const fullNameAtom = atom(
  (get) => `${get(firstNameAtom)} ${get(lastNameAtom)}`,
  'fullName'
);

function Profile() {
  const [fullName] = useAtom(fullNameAtom, store);
  
  return <div>{fullName}</div>;
}

Multiple Stores

javascript
const store1 = createStore();
const store2 = createStore();

function Component1() {
  const [value] = useAtom(atom1, store1);
  return <div>{value}</div>;
}

function Component2() {
  const [value] = useAtom(atom2, store2);
  return <div>{value}</div>;
}

Complete Example: Form with Validation

javascript
import { atom, createStore } from '@nexus-state/core';
import { useAtom } from '@nexus-state/react';
import { devTools } from '@nexus-state/devtools';

// User form atoms
const firstNameAtom = atom('John', 'firstName');
const lastNameAtom = atom('Doe', 'lastName');
const ageAtom = atom(30, 'age');
const emailAtom = atom('john.doe@example.com', 'email');

// Computed atoms
const fullNameAtom = atom(
  (get) => `${get(firstNameAtom)} ${get(lastNameAtom)}`,
  'fullName'
);

const isAdultAtom = atom(
  (get) => get(ageAtom) >= 18,
  'isAdult'
);

const emailValidAtom = atom(
  (get) => /\S+@\S+\.\S+/.test(get(emailAtom)),
  'emailValid'
);

const isValidAtom = atom(
  (get) => {
    const age = get(ageAtom);
    const firstName = get(firstNameAtom).trim().length > 0;
    const lastName = get(lastNameAtom).trim().length > 0;
    const emailValid = get(emailValidAtom);
    
    return age >= 0 && age <= 150 && firstName && lastName && emailValid;
  },
  'isValid'
);

// Create store with DevTools
const store = createStore();
const devtoolsPlugin = devTools();
devtoolsPlugin.apply(store);

function UserForm() {
  const [firstName, setFirstName] = useAtom(firstNameAtom, store);
  const [lastName, setLastName] = useAtom(lastNameAtom, store);
  const [age, setAge] = useAtom(ageAtom, store);
  const [email, setEmail] = useAtom(emailAtom, store);
  const [fullName] = useAtom(fullNameAtom, store);
  const [isAdult] = useAtom(isAdultAtom, store);
  const [isValid] = useAtom(isValidAtom, store);
  
  const handleSubmit = (e) => {
    e.preventDefault();
    if (isValid) {
      console.log('Form submitted:', {
        firstName,
        lastName,
        age,
        email,
        fullName
      });
    }
  };
  
  return (
    <form onSubmit={handleSubmit} style={{ padding: '20px' }}>
      <h2>User Information</h2>
      
      <div style={{ marginBottom: '15px' }}>
        <label style={{ display: 'block', marginBottom: '5px' }}>
          First Name:
        </label>
        <input
          type="text"
          value={firstName}
          onChange={(e) => setFirstName(e.target.value)}
          style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
        />
      </div>
      
      <div style={{ marginBottom: '15px' }}>
        <label style={{ display: 'block', marginBottom: '5px' }}>
          Last Name:
        </label>
        <input
          type="text"
          value={lastName}
          onChange={(e) => setLastName(e.target.value)}
          style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
        />
      </div>
      
      <div style={{ marginBottom: '15px' }}>
        <label style={{ display: 'block', marginBottom: '5px' }}>
          Age:
        </label>
        <input
          type="number"
          value={age}
          onChange={(e) => setAge(parseInt(e.target.value) || 0)}
          style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
        />
      </div>
      
      <div style={{ marginBottom: '15px' }}>
        <label style={{ display: 'block', marginBottom: '5px' }}>
          Email:
        </label>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
        />
      </div>
      
      <div style={{ marginBottom: '15px' }}>
        <h3>Computed Values</h3>
        <p><strong>Full Name:</strong> {fullName}</p>
        <p><strong>Is Adult:</strong> {isAdult ? 'Yes' : 'No'}</p>
        <p><strong>Form Valid:</strong> {isValid ? 'Yes' : 'No'}</p>
      </div>
      
      <button type="submit" disabled={!isValid}>
        Submit Form
      </button>
    </form>
  );
}

Selective Updates

React components only re-render when their specific atoms change:

javascript
// Only this component updates when firstNameAtom changes
function FirstNameDisplay() {
  const [firstName] = useAtom(firstNameAtom, store);
  return <div>{firstName}</div>;
}

// Only this component updates when lastNameAtom changes
function LastNameDisplay() {
  const [lastName] = useAtom(lastNameAtom, store);
  return <div>{lastName}</div>;
}

// This component updates when EITHER atom changes
function FullNameDisplay() {
  const [fullName] = useAtom(fullNameAtom, store);
  return <div>{fullName}</div>;
}