Presentational и в Redux. В настоящее время вы подключены к Redux, но вы управляете состоянием локально в составе Presentational компонента. Presentational сначала удалите свойство messages в локальном state . Эти сообщения будут управляться Redux. Затем измените метод submitMessage() так, чтобы он отправил submitNewMessage() из this.props и передал текущее сообщение из локального state в качестве аргумента. Поскольку вы удалили messages из локального состояния, удалите свойство messages из вызова this.setState() здесь. Наконец, измените метод render() чтобы он отображал сообщения, полученные из props а не state . После внесения этих изменений приложение будет продолжать функционировать одинаково, за исключением того, что Redux управляет состоянием. В этом примере также показано, как компонент может иметь локальное state : ваш компонент по-прежнему отслеживает ввод пользователя локально в своем собственном state . Вы можете видеть, как Redux предоставляет полезную структуру управления государственными ресурсами поверх React. Вы достигли того же результата, используя сначала локальное состояние React, и это обычно возможно с помощью простых приложений. Однако, поскольку ваши приложения становятся все больше и сложнее, так же как и ваше управление состоянием, и это проблема, которую решает Redux. AppWrapper должен отобразить страницу.
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").length === 1; })(), "The AppWrapper should render to the page.");'
- text: 'Presentational компонент должен отображать элементы h2 , input , button и 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: 'Presentational компонент должен отображать элементы h2 , input , button и 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: Presentational компонент должен получать messages от магазина Redux в качестве опоры.
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: Presentational компонент должен получить создателя действия submitMessage в качестве опоры.
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: 'Состояние компонента Presentational должно содержать одно свойство, input , которое инициализируется пустой строкой.'
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: Ввод в элемент input должен обновить состояние компонента 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: При submitMessage на Presentational компоненте необходимо обновить хранилище 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 === "", "Dispatching the submitMessage on the Presentational component should update Redux store and clear the input in local state."); }; '
- text: Presentational компонент должен отображать messages из магазина 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."); }; '
```