---
id: 5a24c314108439a4d4036148
title: 將 Redux 連接到 Messages App
challengeType: 6
forumTopicId: 301427
dashedName: connect-redux-to-the-messages-app
---
# --description--
知道如何使用 `connect` 連接 React 和 Redux 後,我們可以在 React 組件中應用上面學到的內容。
在上一課,連接到 Redux 的組件命名爲 `Presentational`,這個命名不是任意的, 這樣的術語*通常*是指未直接連接到 Redux 的 React 組件, 它們只負責執行接收 props 的函數來實現 UI 的呈現。 相比之下,容器組件用來連接到 Redux 上。 這些組件通常負責把 actions 分派給 store,且經常給子組件傳入 store state 屬性。
# --instructions--
到目前爲止,我們的編輯器上已包含了整個章節的代碼, 唯一不同的是,React 組件被重新命名爲 `Presentational`,即展示層組件。 創建一個新組件,保存在名爲 `Container` 的常量中。 這個常量用 `connect` 把 `Presentational` 組件和 Redux 連接起來。 然後,在`AppWrapper` 中渲染 React Redux 的 `Provider`組件, 給 `Provider` 傳入 Redux `store` 屬性並渲染 `Container` 爲子組件。 設置完所有內容後,將再次看到消息應用程序渲染到頁面上。
# --hints--
`AppWrapper` 應該渲染該到頁面上。
```js
assert(
  (function () {
    const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
    return mockedComponent.find('AppWrapper').length === 1;
  })()
);
```
`Presentational` 應該渲染到頁面上.
```js
assert(
  (function () {
    const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
    return mockedComponent.find('Presentational').length === 1;
  })()
);
```
`Presentational` 組件應渲染 `h2`、`input`、`button`、`ul` 四個元素。
```js
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
    );
  })()
);
```
`Presentational` 組件應接收 Redux store 的 `messages` 屬性。
```js
assert(
  (function () {
    const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
    const PresentationalComponent = mockedComponent.find('Presentational');
    const props = PresentationalComponent.props();
    return Array.isArray(props.messages);
  })()
);
```
`Presentational` 組件應接收創建 action 的函數的 `submitMessage` 屬性。
```js
assert(
  (function () {
    const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
    const PresentationalComponent = mockedComponent.find('Presentational');
    const props = PresentationalComponent.props();
    return typeof props.submitNewMessage === 'function';
  })()
);
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(, document.getElementById('root'))
```
## --seed-contents--
```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:
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((state) => {
      const currentMessage = state.input;
      return {
        input: '',
        messages: state.messages.concat(currentMessage)
      };
    });
  }
  render() {
    return (
      
    );
  }
};
// React-Redux:
const mapStateToProps = (state) => {
  return { messages: state }
};
const mapDispatchToProps = (dispatch) => {
  return {
    submitNewMessage: (newMessage) => {
       dispatch(addMessage(newMessage))
    }
  }
};
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// Define the Container component here:
class AppWrapper extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    // Complete the return statement:
    return (null);
  }
};
```
# --solutions--
```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:
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((state) => {
      const currentMessage = state.input;
      return {
        input: '',
        messages: state.messages.concat(currentMessage)
      };
    });
  }
  render() {
    return (
      
    );
  }
};
// React-Redux:
const mapStateToProps = (state) => {
  return { messages: state }
};
const mapDispatchToProps = (dispatch) => {
  return {
    submitNewMessage: (newMessage) => {
       dispatch(addMessage(newMessage))
    }
  }
};
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      
        
      
    );
  }
};
```