--- id: 5a24c314108439a4d4036149 title: Extract Local State into Redux challengeType: 6 isRequired: false videoUrl: '' localeTitle: Extraer el estado local en Redux --- ## Description
¡Ya casi terminas! Recuerde que escribió todo el código de Redux para que Redux pudiera controlar la administración del estado de su aplicación de mensajes React. Ahora que Redux está conectado, debe extraer la administración del estado del componente de Presentational y en Redux. Actualmente, tiene Redux conectado, pero está manejando el estado localmente dentro del componente de Presentational .
## Instructions
En el componente Presentational , primero, elimine la propiedad de messages en el state local. Estos mensajes serán gestionados por Redux. A continuación, modifique el método submitMessage() para que submitNewMessage() desde this.props , y pase la entrada del mensaje actual del state local como un argumento. Como también eliminó los messages del estado local, elimine la propiedad de messages de la llamada a this.setState() aquí. Finalmente, modifique el método render() para que se asigne sobre los mensajes recibidos de los props lugar del state . Una vez que se realicen estos cambios, la aplicación continuará funcionando de la misma manera, excepto que Redux administra el estado. Este ejemplo también ilustra cómo un componente puede tener un state local: su componente aún realiza un seguimiento local de las entradas del usuario en su propio state . Puede ver cómo Redux proporciona un marco de administración de estado útil sobre React. Obtuvo el mismo resultado utilizando solo el estado local de React al principio, y esto generalmente es posible con aplicaciones simples. Sin embargo, a medida que sus aplicaciones se vuelven más grandes y complejas, también lo hace la administración de su estado, y este es el problema que Redux resuelve.
## Tests
```yml tests: - text: El AppWrapper debe renderizar a la página. testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").length === 1; })(), "The AppWrapper should render to the page.");' - text: 'El componente de Presentational debe representar los elementos h2 , input , button y ul .' testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("Presentational").length === 1; })(), "The Presentational component should render an h2, input, button, and ul elements.");' - text: 'El componente de Presentational debe representar los elementos h2 , input , button y ul .' testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); return ( PresentationalComponent.find("div").length === 1 && PresentationalComponent.find("h2").length === 1 && PresentationalComponent.find("button").length === 1 && PresentationalComponent.find("ul").length === 1 ); })(), "The Presentational component should render an h2, input, button, and ul elements.");' - text: El componente de Presentational debe recibir messages de la tienda de Redux como prop. testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return Array.isArray(props.messages); })(), "The Presentational component should receive messages from the Redux store as a prop.");' - text: El componente de Presentational debe recibir el creador de la acción submitMessage como prop. testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return typeof props.submitNewMessage === "function"; })(), "The Presentational component should receive the submitMessage action creator as a prop.");' - text: 'El estado del componente Presentational debe contener una propiedad, input , que se inicializa en una cadena vacía.' testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalState = mockedComponent.find("Presentational").instance().state; return typeof PresentationalState.input === "string" && Object.keys(PresentationalState).length === 1; })(), "The state of the Presentational component should contain one property, input, which is initialized to an empty string.");' - text: Escribir en el elemento de input debe actualizar el estado del componente de Presentational . testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const testValue = "__MOCK__INPUT__"; const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); let initialInput = mockedComponent.find("Presentational").find("input"); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const updated = await changed(); const updatedInput = updated.find("Presentational").find("input"); assert(initialInput.props().value === "" && updatedInput.props().value === "__MOCK__INPUT__", "Typing in the input element should update the state of the Presentational component."); }; ' - text: El envío del submitMessage en el componente de Presentational debe actualizar el almacén de Redux y borrar la entrada en el estado local. testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find("Presentational").props(); const testValue = "__TEST__EVENT__INPUT__"; const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find("input").props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find("Presentational").props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find("input").props().value === "", "Dispatching the submitMessage on the Presentational component should update Redux store and clear the input in local state."); }; ' - text: El componente de Presentational debe representar los messages del almacén de Redux. testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find("Presentational").props(); const testValue = "__TEST__EVENT__INPUT__"; const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find("input").props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find("Presentational").props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find("input").props().value === "" && afterClick.find("ul").childAt(0).text() === testValue, "The Presentational component should render the messages from the Redux store."); }; ' ```
## Challenge Seed
```jsx // Redux: const ADD = 'ADD'; const addMessage = (message) => { return { type: ADD, message: message } }; const messageReducer = (state = [], action) => { switch (action.type) { case ADD: return [ ...state, action.message ]; default: return state; } }; const store = Redux.createStore(messageReducer); // React: const Provider = ReactRedux.Provider; const connect = ReactRedux.connect; // Change code below this line class Presentational extends React.Component { constructor(props) { super(props); this.state = { input: ", messages: [] } this.handleChange = this.handleChange.bind(this); this.submitMessage = this.submitMessage.bind(this); } handleChange(event) { this.setState({ input: event.target.value }); } submitMessage() { this.setState({ input: ", messages: this.state.messages.concat(this.state.input) }); } render() { return (

Type in a new Message:


    {this.state.messages.map( (message, idx) => { return (
  • {message}
  • ) }) }
); } }; // Change code above this line const mapStateToProps = (state) => { return {messages: state} }; const mapDispatchToProps = (dispatch) => { return { submitNewMessage: (message) => { dispatch(addMessage(message)) } } }; const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational); class AppWrapper extends React.Component { render() { return ( ); } }; ```
### After Test
```js console.info('after the test'); ```
## Solution
```js // solution required ```