fetch values into the effector store

1.7k Views Asked by At

I'm facing the problem with the effector (state manager)

  1. The user is signing in and then I'm making the get request to get user info
  2. I need to store that info in the effector store to use it later

This is my models/user/index.ts :

import { combine, createEffect, createEvent, createStore, restore } from 'effector';

import { User } from './types';

export const $user = createStore<User[]>([]);

export const fetchUserInfoFx = createEffect<void, User, Error>();

This is models/user/init.ts

import { $user, fetchUserInfoFx } from '.';

fetchUserInfoFx.use(async () => {
  const response = await fetch('http://localhost:5000/auth/me', { credentials: 'include' });
  const data = await response.json();

  const id = data.id === null ? '' : data.id;
  const username = data.username === null ? '' : data.username;
  const fullname = data.fullname === null ? '' : data.fullname;

  return { id, username, fullname };
});

$user.on(fetchUserInfoFx.doneData, (data) => data);

This is models/user/types.ts :

export type User = {
  id: string;
  username: string;
  fullname: string;
};

Could you please help ? I'm new to effector, So don't know why I can't fetch user info into the store. Moreover, I'm 100% sure that I get all the values from the fetch call. Just don't know how to pass them into the store. Thanks!

1

There are 1 best solutions below

0
jsejcksn On

Observation: Your store variable is called $user, but its type is User[] and the initialized value is an empty array, so I'm going to presume that you want multiple users in your store, and I'll rename it $users in the code below.

Here are the docs for $store.on(trigger, reducer).

In your example reducer, you never modify the store (you just return it every time the reducer is invoked), so the data in the store never changes, no matter how many times the effect is run. This is how you can append users to the array using an effect:

TS Playground

import {createEffect, createStore} from 'effector';

type ValuesIncludingType<Obj, Type> = { [K in keyof Obj]: Obj[K] | Type; };

type User = {
  id: string;
  username: string;
  fullname: string;
};

async function fetchUserData (): Promise<User> {
  const response = await fetch('http://localhost:5000/auth/me', { credentials: 'include' });
  const data = await response.json() as ValuesIncludingType<User, null>; /*
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  This assertion tells TS that data is of type User, and that
  its properties could be 'string' or 'null' */

  return { // using the nullish coalescing operator makes the statements much shorter
    fullname: data.fullname ?? '',
    id: data.id ?? '',
    username: data.username ?? '',
  };
}

const fetchUserInfoFx = createEffect<void, User>();
fetchUserInfoFx.use(fetchUserData);

const $users = createStore<User[]>([]);
$users.on(fetchUserInfoFx.doneData, (users, newUser) => [...users, newUser]); /*
                                                        ^^^^^^^^^^^^^^^^^^^
Spread the existing users into a new array, and include the new user at the end */