React and Redux: Part 2

  • Hello again! Let's continue forward with the last of these lessons for this particular section.
  • In the last post we created Redux store to handle the messages array and created an action for adding new messages. Now we need to provide React access to the Redux store and the actions it needs to dispatch updates.
  • React Redux provides a small API with two key features: Provider and connect.
  • Here we'll focus on Provider. It's a wrapper component from React Redux that wraps your React app. Which then allows us to access the Redux store and dispatch functions throughout our component tree.
  • Provider takes two props, the Redux store and the child components of our app.
  • It will look like this.
// Redux:
const ADD = 'ADD';

const addMessage = (message) => {
  return {
    type: ADD,
    message
  }
};

const messageReducer = (state = [], action) => {
  switch (action.type) {
    case ADD:
      return [
        ...state,
        action.message
      ];
    default:
      return state;
  }
};



const store = Redux.createStore(messageReducer);

// React:

class DisplayMessages 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 (
      <div>
        <h2>Type in a new Message:</h2>
        <input
          value={this.state.input}
          onChange={this.handleChange}/><br/>
        <button onClick={this.submitMessage}>Submit</button>
        <ul>
          {this.state.messages.map( (message, idx) => {
              return (
                 <li key={idx}>{message}</li>
              )
            })
          }
        </ul>
      </div>
    );
  }
};

const Provider = ReactRedux.Provider;

class AppWrapper extends React.Component {
  // Render the Provider below this line
  render() {
    return (
    <Provider store={store}>
    <DisplayMessages/>
    </Provider>
    )
  }

};
  • As you can see, we rendered the Provider from ReactRedux and passed the Redux store as a prop. Then we rendered the DisplayMessages component as a child. Once we finished, we can see our React component rendered to the page.

  • Obviously there's a lot more to learn about this but I'm just basics.

Map State to Props

  • The Provider component allows you to provide state and dispatch to your React components, but you must specify exactly what state and actions you want.
  • You can accomplish this by creating two functions: mapStateToProps() and mapDispatchToProps().
  • With these functions, you declare what pieces of state you want to have access to and which action creators you need to be able to dispatch.
  • FreeCodeCamp wants us to create a function mapStateToProps. For this function it will take state as an argument, then return an object which maps that state to specific property names. Then create a property messages in the object that's being returned and set it to state.
const state = [];

function mapStateToProps(state) {
  return {
    messages: state
  }
}
  • The properties become available to our component via props. FreeCodeCamp provides us with the store.subscribe method to implement mapStateToProps() behind the scenes.

Map Dispatch to Props

  • The mapDispatchToProps() function is used to provide specific action creators to your React components so they can dispatch actions against the Redux store. It also returns an object that maps dispatch actions to property names, which become component props. With that, each property returns a function that calls dispatch with an action creator and any relevant action data.
  • We have access to this dispatch because it's passed in to mapDispatchToProps() as a parameter when you define the function, just like you passed state to mapStateToProps()
  • Behind the scenes, React Redux is using Redux's store.dispatch
  • Example, we have a addMessage() action creator that takes a message as an action payload. The object returned from mapDispatchToProps() for this action creator would look like this.
const addMessage = (message) => {
  return {
    type: 'ADD',
    message: message
  }
};

function mapDispatchToProps(dispatch) {
  return {
    submitNewMessage: (message) => {
      dispatch(addMessage(message))
    }
  }
}
  • The object here has a property submitNewMessage set to the dispatch function, which takes a parameter for the new message to add when it dispatches addMessage().

Connect Redux to React

  • Now that we've written both the mapStateToProps and the mapDispatchToProps functions, you can use them to map state and dispatch to the props of one of our React components.
  • The connect method has two optional arguments, mapStateToProps() and mapDispatchToProps(). They are optional because you may have a component that only needs access to state but doesn't need to dispatch any actions, or vice versa.
  • To use such method, you'll have to pass in the functions as arguments, and then call the result with our component. It will look like so:
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
  • FreeCodeCamp wants us to connect the component Presentational to Redux with the connect method from the ReactRedux global object, and call it on the Presentational component. Assigning the result to a new const called ConnectedComponent that represents the connected component.
const addMessage = (message) => {
  return {
    type: 'ADD',
    message: message
  }
};

const mapStateToProps = (state) => {
  return {
    messages: state
  }
};

const mapDispatchToProps = (dispatch) => {
  return {
    submitNewMessage: (message) => {
      dispatch(addMessage(message));
    }
  }
};

class Presentational extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <h3>This is a Presentational Component</h3>
  }
};

const connect = ReactRedux.connect;
  • Answer:
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Presentational)
  • Here the The Presentational component received a prop messages via connect and received a prop submitNewMessage via connect.

Connect Redux to the Messages App

  • With learning about how to use connect we can now apply what we've learned to our React Component that handles messages.
  • Container components are connected to Redux. These are typically responsible for dispatching actions to the store and pass store state to child components as props.
  • Here FreeCodeCamp wants us to create a new component const called Container that uses connect to connect the Presentational component to Redux. Then, in the AppWrapper, render the React Redux Provider component. Pass Provider the Redux store as a prop and render Container as a child. Once everything is setup, you will see the messages app rendered to the page.
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);
  }
};
  • Answer:
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 (
      <Provider store={store}>
      <Container/>

      </Provider>
    );
  }
};

Extract Local State into Redux

  • Nice work! Just like me you're learning about React and Redux and all it's wonders this isn't the end though. There's still so much we have to work towards and learn more about. Please don't give up on making things happen.
  • Let's recall that you wrote all the Redux code so that Redux could control the state management of your React messages app. Now that Redux is connected, you need to extract the state management out of the Presentational component and into Redux. We have Redux connected, but we are handling the state locally within the Presentational component.
  • FreeCodeCamp wants us In the Presentational component, remove the messages property in the local state. These messages will be managed by Redux.
  • Next, modify the submitMessage() method so that it dispatches submitNewMessage() from this.props, and pass in the current message input from local state as an argument. Because you removed messages from local state, remove the messages property from the call to this.setState() here as well. Finally, modify the render() method so that it maps over the messages received from props rather than state.
submitMessage() {
    this.setState((state) => ({
      input: '',
      messages: state.messages.concat(state.input)
    }));
  }
  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
        <input
          value={this.state.input}
          onChange={this.handleChange}/><br/>
        <button onClick={this.submitMessage}>Submit</button>
        <ul>
          {this.state.messages.map( (message, idx) => {
              return (
                 <li key={idx}>{message}</li>
              )
            })
          }
        </ul>
      </div>
    );
  }
};
  • Answer:
submitMessage() {
   this.props.submitNewMessage(this.state.input)
    this.setState({
      input: ''
    })
  }
  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
        <input
          value={this.state.input}
          onChange={this.handleChange}/><br/>
        <button onClick={this.submitMessage}>Submit</button>
        <ul>
          {this.props.messages.map( (message, idx) => {
              return (
                 <li key={idx}>{message}</li>
              )
            })
          }
        </ul>
      </div>
    );
  }
};
  • And that is it for the React and Redux Lesson on freeCodeCamp. Thank you so much for reading these as I go through them. Helping myself and others,

Larson, Q., 2019. Frontend Development Libraries. [online] Freecodecamp.org. Available at: https://www.freecodecamp.org/learn/front-end-development-libraries/react-and-redux

This can get complicated quickly. there's a link below if you want to experiment on your own machine, the Create React App comes configured and ready to go.

23