No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

20 Días
0 Hrs
30 Min
6 Seg

Contexto

10/15
Recursos

Aportes 14

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

🤿 Contexto

Ideas/conceptos claves

Contexto

Es una parte extendida de la máquina de estados

Apuntes

  • El contexto en general nos ayudará a guardar datos

Establecer un contexto inicial

import { createMachine, assign } from "xstate";

const bookingMachine = createMachine({
		...,
    context: {
			// Objeto de contexto
      passengers: [],
      selectedCountry: "",
    },
    states: {...}
	}
);

Leer Contexto

import { useMachine } from "@xstate/react";

export const BaseLayout = () => {
  const [state, send] = useMachine(bookingMachine);

  console.log("nuestro contexto", state.context);

  return ( ... );
};

Actualizar contexto

const bookingMachine = createMachine(
  {
    ...,
    states: {
      ...,
      search: {
        on: {
          CONTINUE: {
            target: "passengers",
            // 1️⃣ Primera Forma: Pasando un objeto a la función assign,
            // En el mismo se debe especificar las propiedades a modificar
            actions: assign({
              selectedCountry: (context, event) => event.selectedCountry,
            }),
          },
          // 2️⃣ Segunda forma: Llamando a una accción definida en el machine
          CANCEL: { target: "initial", actions: "cleanContext" },
        },
      },
      passengers: {
        on: {
          ADD: {
            target: "passengers",
            // 3️⃣ Tercera forma: Modificando directamente el objeto de contexto
            // pasando una función al objeto assign
            actions: assign((context, event) =>
              context.passengers.push(event.newPassenger)
            ),
          },
        },
      },
    },
  },
  {
    actions: {
      cleanContext: assign({
        selectedCountry: "",
        passengers: [],
      }),
    },
  }
);
Para asignar correctamente el contexto en la versión 5 de XState: ```js actions: assign({ selectedCountry: ({ event }) => event.selectedCountry, }) ```

Como solución al reto creo que lo mas eficiente seri únicamente que cuando se regrese al estado inicial la información se resetee
Únicamente en el bookingMachine.Js

 initial: {
        entry: assign((context, event) => {
            context.passengers = []
            context.selectedCountry = ""

        }),
        on: {
          START: {
            target: "search",
          },
        },
      },
![](https://static.platzi.com/media/user_upload/image-5e08e526-4851-474a-a683-246aabb718d2.jpg)Hay un error con el video :(

mi aporte al reto:
src/Machines/bookingMachine.js:

const bookingMachine = createMachine({
  id: ".... ",
  initial: "....",
  context: {
    passengers: [],
    selectedCountry: '',
  },
  states: {
    initial: {
      ...
    },
    search: {
      ...
    },
    tickets: {
      ...
    },
    passengers: {
      on: {
        DONE: "tickets",
        CANCEL: {
          target: 'initial',
          actions: assign({
            selectedCountry: (context, event) => event.selectedCountry,
            passengers: (context, event) => event.passengers
          })
        },
        ADD: {
          ...
        }
      },
    },
  },
}, 
);

src/Components/Nav.js:

export const Nav = ({ state, send }) => {
  
  const goToWelcome = ()=> {
    send('CANCEL', { selectedCountry: '', passengers: [] })
  }

  return (
    <nav className='Nav'>
      ....
        {!state.matches('initial') && 
          <button onClick={goToWelcome} className='Nav-cancel button-secondary'>Cancelar</button>
        }
    </nav>
  );
}; 

src/Components/Passengers.js:

import bookingMachine from '../Machines/bookingMachine';

export const Passengers = ({ state, send }) => {

  return (
    <form onSubmit={submit} className='Passengers'>
      ....
      {bookingMachine.context.passengers.map((passenger,index) => (
        <p key={`${passenger}${index}`}>{passenger}</p>
      ))}
      ...
    </form>
  );
};

.
.

codigo completo:
src/Machines/bookingMachine.js:

import { createMachine, assign } from "xstate";

const bookingMachine = createMachine({
  id: "buy plane tickets",
  initial: "initial",
  context: {
    passengers: [],
    selectedCountry: '',
  },
  states: {
    initial: {
      on: {
        START: { 
          target: 'search',
        },
      },
    },
    search: {
      on: {
        CONTINUE: {
          target: 'passengers',
          actions: assign({
            selectedCountry: (context, event) => event.selectedCountry
          })
        },
        CANCEL: 'initial',
      },
    },
    tickets: {
      on: {
        FINISH: "initial",
      },
    },
    passengers: {
      on: {
        DONE: "tickets",
        CANCEL: {
          target: 'initial',
          actions: assign({
            selectedCountry: (context, event) => event.selectedCountry,
            passengers: (context, event) => event.passengers
          })
        },
        ADD: {
          target: 'passengers',
          actions: assign(
            (context, event)=> context.passengers.push(event.newPassenger) 
          )
        }
      },
    },
  },
}, 
);

export default bookingMachine;

src/Components/Nav.js:

import React from 'react';
import './Nav.css';

export const Nav = ({ state, send }) => {
  
  const goToWelcome = ()=> {
    send('CANCEL', { selectedCountry: '', passengers: [] })
  }

  return (
    <nav className='Nav'>
      <h1 className='Nav-logo'>Book a fly ✈</h1>
        {!state.matches('initial') && 
          <button onClick={goToWelcome} className='Nav-cancel button-secondary'>Cancelar</button>
        }
    </nav>
  );
}; 

src/Components/Passengers.js:

import React, { useState } from 'react';
import bookingMachine from '../Machines/bookingMachine';
import './Passengers.css';

export const Passengers = ({ state, send }) => {
  const [value, changeValue] = useState('');

  const onChangeInput = (e) => {
    changeValue(e.target.value);
  }

  const goToTicket = ()=> {
    send('DONE')
  }

  const submit = (e) => {
    e.preventDefault();
    send('ADD', { newPassenger: value })
    changeValue('');
  }

  return (
    <form onSubmit={submit} className='Passengers'>
      <p className='Passengers-title title'>Agrega a las personas que van a volar ✈️</p>
      {bookingMachine.context.passengers.map((passenger,index) => (
        <p key={`${passenger}${index}`}>{passenger}</p>
      ))}
      <input 
        id="name" 
        name="name" 
        type="text" 
        placeholder='Escribe el nombre completo' 
        required 
        value={value} 
        onChange={onChangeInput}
      />
      <div className='Passengers-buttons'>
        <button 
          className='Passengers-add button-secondary'
          type="submit"
        >
          Agregar Pasajero
        </button>
        <button
          className='Passenger-pay button'
          type="button"
          onClick={goToTicket}
        >
          Ver mi ticket
        </button>
      </div>
    </form>
  );
}
Si estás viendo este vídeo muchas cosas han cambiado por lo que te recomiendo que tengas la documentación a la mano, en el assign sería assign({ value:({event})=>event.vale }) pero bueno así también puedes practicar como ir leyendo la documentación jajja
Reto Completado ```js import React, { useContext } from "react"; import "./Tickets.css"; import { XStateContext } from "../XStateContext"; export const Tickets = () => { const { send, state } = useContext(XStateContext); const { passengers, selectedCountry } = state.context; const handleFinish = () => { send("FINISH"); }; return (

Gracias por volar con book a fly 💚

{selectedCountry}
{passengers.map((passenger) => { return

{passenger}

; })}
<button onClick={handleFinish} className="Tickets-finalizar button"> Finalizar </button>
); }; ``` ```js import { assign, createMachine } from "xstate"; const contextDefault = () => ({ passengers: [], selectedCountry: "", }) const bookingMachine = createMachine( { id: "buy plane tickets", initial: "initial", context: contextDefault(), states: { initial: { entry: "resetContext" , on: { START: { target: "search", actions: "printStart", }, }, }, search: { entry: "printEntry", exit: "printExit", on: { CONTINUE: { target: "passengers", actions: assign({ selectedCountry: (context, e) => e.selectedCountry, }), }, CANCEL: { target : "initial", actions: "resetContext" } }, }, tickets: { on: { FINISH: { target: "initial", actions: "resetContext" }, }, }, passengers: { on: { DONE: "tickets", CANCEL: { target: "initial", actions: "resetContext" }, ADD: { target: "passengers", actions: assign((context, e) => ({ passengers: [...context.passengers, e.newPassengers] })) } }, }, }, }, { actions: { printStart: () => console.log("Inicio"), printEntry: () => console.log("Entrada"), printExit: () => console.log("Salida"), resetContext: assign(() => contextDefault()) }, } ); export default bookingMachine; ```
```js passengers: { on: { DONE: "tickets", ADD: { target:"passengers", actions: assign({ passengerNames: ({context, event}) => [...context.passengerNames, event.newPassenger] }) }, ``` Asi quedaria mi solucion sin usar push porque push cambia la array original y el contexto es inmutable.

Dejo código de la clase con TypeScript y Vite
Definimos contexto

Leer contexto

Modificar contexto
Primero definimos evento y enviamos la información



Finalmente se define la modificacion
Utilizando assing de xstate

o de forma directa

Alternativa a listar, lo puse como otros inputs

En los estados de search y Passenger agregué lo siguientes en cada evento CANCEL:

y en el componente Nav agregué lo siguiente:

import React from 'react';
import '@styles/Nav.css';

export const Nav = ({ state, send }) => {

  const goToInitial = () => {  
    send("CANCEL", {newPassenger: [], selectedCountry: ""});
  }

  return (
    <nav className='Nav'>
      <h1 className='Nav-logo'>Book a fly ✈</h1>
      {
        !state.matches("initial") && 
        <button className='Nav-cancel button-secondary' onClick={goToInitial}>Cancelar</button>
      }
    </nav>
  );
}; 

En el reto de agregar los nombres de los pasajeros hice lo siguiente:

{state.context.passenger.map((user) => <p key={user}>{user}</p>)}

En el componente Passenger agregué esta linea dentro del formulario y encima del input. Recojo los datos del contexto almacenados en passenger y con un .map agrego etiquetas <p> con cada nombre de pasajeros que esté en el array.

Solución al reto 2:

StepsLayout.js

export const StepsLayout = ({ state, send }) => {
  const renderContent = () => {
    ...
    if(state.matches('passengers')) return <Passengers send={send} state={state} />;

    return null;
  };
}; 

Passengers.js

export const Passengers = ({ state, send }) => {
  
  return (
    <form onSubmit={submit} className='Passengers'>
      <p className='Passengers-title title'>Agrega a las personas que van a volar ✈️</p>
      {state.context.passengers.length > 0 && state.context.passengers.map((passenger) => (
        <p>{passenger}</p>
      ))}
	...
    </form>
  );
};

En bookMachine - passengers

        CANCEL:{
          target: "inicial",
          actions: assign((context, event) => (context.passengers = [], context.selectedCountry = '')),
        },

Aunque no le convence mucho a Visual la coma del medio.

reto 1 y reto 2 cumplidos, el código quedo de la siguiente manera:

bookingMachine.js:

import { assign, createMachine } from "xstate";

const reset = assign({
  passengers: (_, event) => event.passengers = [],
  selectedCountry: (_, event) => event.selectedCountry = "",
});

const bookingMachine = createMachine({
  id: "buy plane tickets",
  initial: "initial",
  context: {...
},
  states: {...
},
    search: {
      on: {
        CONTINUE: {...
          },
        CANCEL: {
          target: "initial",
          actions: reset
        },
      },
    },
    passengers: {
      on: {
        DONE: "tickets",
        CANCEL: {
          target: "initial",
          actions: reset
        },
        BACK: "search",
        ADD: {...
          }
      },
    },
    tickets: {
      on: {
        FINISH: {
          target: "initial",
          actions: reset
        },
        CANCEL: {
          target: "initial",
          actions: reset
        },
        BACK: "passengers",
      },
    },
  },
} ...

Y el reto 2:
StepsLayout.js:

if(state.matches('passengers')) return <Passengers send={send} state={state} />;

Passengers.js:

return (
    <form onSubmit={submit} className='Passengers'>
      <p className='Passengers-title title'>Agrega a las personas que van a volar ✈️</p>
      <ul className='Passengers-list'>
        {state.context.passengers.map((passenger, index) => (
          <li key={index} className='Passengers-list_li'>
            - {passenger}
          </li>
        ))}
      </ul>
      <input 
        id="name" 
        name="name" 
        type="text" 
        placeholder='Escribe el nombre completo' 
        required 
        value={value} 
        onChange={onChangeInput}
      />

Passengers.css:

.Passengers-list {
  align-self: flex-start;
  list-style: none;
  padding: 0;
  text-align: start;
}

.Passengers-list_li {
  margin-bottom: 6px;
}