Udemy - React with Redux Flashcards

1
Q

What is a connected component?

A

A React component that’s connected to the Redux store.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What happens when a React component is connected to the Redux store?

A

The components are going to be able to fetch data off the redux store so they can render something to the screen and when that data that they fetch changes, they’re automatically going to get rerendered so we always have the interface up to date with the latest changes to the redux store. We’ll also be able to dispatch actions directly from our React components. If we have a React component with a from, someone can fill out that data, submit the form and the React component can dispatch he necessary action to change the stores data.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

How would you export this code as a function?

const store = createStore(
  combineReducers({
    expenses: expensesReducer,
    filters: filtersReducer
  })
);
A
export default () => {
  const store = createStore(
    combineReducers({
      expenses: expensesReducer,
      filters: filtersReducer
    })
  );
  return store;
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Why would you export the createStore() function in another function?

A

When we import the function (the default function (from configureStore.js)), we just call it, we get the store back and we can then use it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

How would you use this function?

export default () => {
  const store = createStore(
    combineReducers({
      expenses: expensesReducer,
      filters: filtersReducer
    })
  );
  return store;
};
A

import configureStore from ‘./store/configureStore’;

const store = configureStore();

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What does store give us access to?

import configureStore from ‘./store/configureStore’;

const store = configureStore();

A

All the things we had before:

store. dispatch()
store. getState()
store. subscribe()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Give a simple example of using store:

import configureStore from ‘./store/configureStore’;

const store = configureStore();

A

console.log(store.getState());

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

How would you add an expense?

A

store.dispatch(addExpense({ description: ‘Water bill’ }));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

How would you set the text filter?

A

store.dispatch(setTextFilter(‘bill’));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

How would you get the visible expenses?

A
const state = store.getState();
const visibleExpenses = getVisibleExpenses(state.expenses, state.filters);
console.log(visibleExpenses);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is React Redux?

A

A library that allows us to connect our redux stores to our react components. It makes heavy use of a pattern known as higher order components.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is a Higher Order Component (HOC)?

A

A component (HOC) that renders another component (regular component).

NOTE: The HOC may render several other components.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How would you create a HOC that renders < Info / >?

const Info = (props)  => (
  < div >
    < h1 >Info< /h1 >
    < p >The info is: {props.info}.< /p >
  < /div >
);

ReactDOM.render(< Info info=”details” / >, docuent.getElementById(‘app’));

NOTE: We’re implicitly returning some JSX.

A

NOTE: The HOC is a stateless functional component that implicitly returns some JSX.

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      < p >This is private info< /p >
      < /WrappedComponent / >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo info=”details” / >, docuent.getElementById(‘app’));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What will HOC allow?

A

To reuse code.
Able to perform render hijacking.
Add a little prop manipulation.
Abstract state.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What are the steps of creating a HOC?

A
  1. Create a (regular) function (not a react component).
  2. This function gets called with another component that we want to wrap.
  3. When you call this (HOC) function, what you get back is an alternative version of the component you pass in (it’s going to be the HOC).
  4. Calling the argument of the (step 1) function, WrappedComponent is a convention. NOTE: it is a component so we do want to start with an upper case first letter.
  5. Inside this function is where we return a new component. NOTE: The component that is created here is the HOC.

see: The Higher Order Component

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What’s the problem with this code?

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      < p >This is private info< /p >
      < /WrappedComponent / >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo info=”details” / >, docuent.getElementById(‘app’));

A

The info component is broken. It’s not getting the props that are passed in.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

How could you fix this code?

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      < p >This is private info< /p >
      < /WrappedComponent / >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo info=”details” / >, docuent.getElementById(‘app’));

A

With the spread operator. When we’re instantiating a component inside of JSX, we can open and close a set of curly braces to create a JavaScript expression. From here, we can spread out any object we like. Here, we spread out props. This has the effect of taking every key value pair on that object and passing them down as props.

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      < p >This is private info< /p >
      < /WrappedComponent {...props}/ >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo info=”details” / >, docuent.getElementById(‘app’));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

How could you provide whether or not you should show the AdminInfo message?

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      < p >This is private info< /p >
      < /WrappedComponent {...props}/ >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo info=”details” / >, docuent.getElementById(‘app’));

A

By passing a special prop into the HOC aswell.
NOTE: We use some

const withAdminWarning = (WrappedComponent) => {
  return (props) => (
    < div >
      { props.isAdmin AND < p >This is private info< /p > }
      < /WrappedComponent {...props}/ >
    < /div >
  );
};

const AdminInfo = withAdminWarning(info);

ReactDOM.render(< AdminInfo isAdmin={true} info=”details” / >, docuent.getElementById(‘app’));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What are we going to be doing a lot with the React Redux library?

A

We’ll be given a function. We’ll pass out function inside of them and the end result will be a new component that we’re going to be using. This component will have access to the redux store.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

How would you create a function that tests whether someone is logged in or not, using this code?

ReactDOM.render(< AuthInfo isAuthenticated={false} info=”details” / >, docuent.getElementById(‘app’));

A

NOTE: RequireAuthentication() isn’t a HOC, it’s just a regular function that returns the HOC.
NOTE: For our purposes, we return a stateless functional component.
NOTE: We implicitly return some JSX.

const requireAuthentication = (WrappedComponent) => {
  return (props) => (
    < div >
      {props.isAuthenticated ? (
        < WrappedComponent {...props} / >
      ) : (
        < p >Please log in< /p >
      )}
    < /div >
  );
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

How can you install the React Redux library?

A

yarn add react-redux@x

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

How many times are we going to use the component?

A

Once.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

How many times are we going to use the < Provider / > component?

A

Once.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Where are we going to use the < Provider / > component?

A

At the root of our application.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

What will we use connect on?

A

Every component that needs to connect to the redux store.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

How do we import the Provider component?

A

NOTE: Provider and connect are named exports.

import { Provider } from ‘./react-redux’;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

How do we use the provider component?

ReactDOM.render(< AppRouter / >, document.getElementById(‘app’));

A
const jsx = (
  < Provider store={store} >
    < AppRouter / >
  < /Provider >
);

ReactDOM.render(jsx, document.getElementById(‘app’));

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

What does Provider allow us to do?

A

To provide the store to all of the components that make up our application.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

Why is Provider useful?

A

Because we don’t have to manually pass the store around. Instead, individual components that want to access the store can just access it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

What prop has to be passed into Provider?

A

The store that we’re trying to share with the rest of the application.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

Can we use connect without having Provider set up?

A

No.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

How would we get the expenses list rendered?

const ExpenseDashboardPage = () => (
  < div >
    This is from my Dashboard component!
  < /div >
);
const ExpenseList = () => (
  < div >
    < h1 >Expense List< /h1 >
  < /div >
);
A

NOTE: This is a stateless functional component.

const ExpenseList = () => (
  < div >
    < h1 >Expense List< /h1 >
  < /div >
);
const ExpenseDashboardPage = () => (
  < div >
    < ExpenseList / >
  < /div >
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q

What does connect do?

A

Connect your component to the redux store.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q

How would you import connect?

A

import { connect } from ‘react-redux’;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

How would you use connect in this code?

const ExpenseList = () => (
  < div >
    < h1 >Expense List< /h1 >
  < /div >
);
const ExpenseDashboardPage = () => (
  < div >
    < ExpenseList / >
  < /div >
);
A

Firstly, you’ll create a new const for the HOC.

const ConnectedExpenseList = connect((state) => {
  return {
    name: 'Chris'
  }
})(ExpenseList);
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.name}
  < /div >
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

Why is calling connect() slightly different than usual?

A

We get something back which is not the HOC. It’s actually the function, which means we need to call that with the component.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

What would you provide in the first argument of connect()()

A

Information about what we want to connect. We have a lot of information on the store and the component doesn’t always/usually need all of it, just a subset. So you define a function.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q

What does the function you pass in as the first argument of connect()() determine?

A

What information from the store we want our component to be able to access.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q

What function would you pass into the first argument of connect()()

A
connect((state) => {
  return {
    name: 'Chris'
  }
})(ExpenseList);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q

What gets passed into the function you pass into the first argument of connect()()

A

the stores state.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q

How does the connect()() functions body work?

A

We return and object. On this object we can put any key value pairs we like. Usually, they’re things from the state but you could pass in name: ‘Chris’. Now the ConnectExpenseList component is going to have access to the name prop. This means in ExpenseList, you can set up props and use the value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q

How would you make this useful?

const ConnectedExpenseList = connect((state) => {
  return {
    name: 'Chris'
  }
})(ExpenseList);
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.name}
  < /div >
);
A

By reading off of the state.

const ConnectedExpenseList = connect((state) => {
  return {
    expenses: state.expenses
  }
})(ExpenseList);
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.expenses.length}
  < /div >
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q

What is a more common pattern than creating a separate variable and then exporting it by default like so?

const ConnectedExpenseList = connect((state) => {
  return {
    expenses: state.expenses
  }
})(ExpenseList);

export default ConnectedExpenseList;

A
export default connect((state) => {
  return {
    expenses: state.expenses
  }
})(ExpenseList);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q

What is a common practice you could take with this code?

export default connect((state) => {
  return {
    expenses: state.expenses
  }
})(ExpenseList);
A

Take the function and break it out into its own variable.

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

export default connect(mapStateToProps)(ExpenseList);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q

What would you do if you also wanted to access the filters?

const mapStateToProps = (state) => {
  return {
    expenses: state.expenses
  }
};
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.expenses.length}
  < /div >
);
A
const mapStateToProps = (state) => {
  return {
    expenses: state.expenses,
    filters: state.filters
  }
};
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.filters.text}
    {props.expenses.length}
  < /div >
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q

What is noteworthy about this code?

const mapStateToProps = (state) => {
  return {
    expenses: state.expenses,
    filters: state.filters
  }
};
A

As the store changes, the function is automatically going to get rerun.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q

What are the arguments you pass into setTimeout()

A

The first is a function and the second is the amount of time you want to wait in milliseconds.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q

Show a simple example of using setTimeout()

A

setTimeout(() => {
store.dispatch(setTextFilter(‘rent’));
}, 3000);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q

What is important to note in regards to when you connect a component to the redux store?

A

That it’s reactive. This means as the store changes, the component is going to get rerendered with those new values.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q

Why is it a good thing that when you connect a component to the redux store, it’s reactive?

A

It allows us to create very simple components.

const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.filters.text}
    {props.expenses.length}
  < /div >
);

For example, this component doesn’t need to worry about using store.subscribe() or store.getState(). It doesn’t have to use any component state to manage that data, instead all of it is done for us by React Redux. All we have to do is define how we want to render things. Therefore, it’s a simple presentational component.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

What is the goal with presentational components?

A

To get as many of the components into presentational component patterns as possible.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q

SEE

A

Connecting Store and Component with React Redux.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q

How would you do something meaningful with the array of expenses in this code?

const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.expenses.length}
  < /div >
);
A

Use map to iterate over the array and render a new instance of of an Expense List Item Component, for each one.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q

How would you create a stateless functional component that renders the description, amount and the created at value and update this code to use it?

const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.expenses.length}
  < /div >
);
A

NOTE: This implicitly returns some JSX.
NOTE: The props object is destructured.
NOTE: You must import React as you are using JSX.
NOTE: We use the spread operator on the < ExpenseListItem / > instance.
NOTE: The key prop is needed.

const ExpenseListItem = ({ description, amount, createdAt }) => (
  < div >
    < h3 >{description}< /h3 >
    < p >{amount} - {createdAt}< /p >
  < /div >
);
const ExpenseList = (props) => (
  < div >
    < h1 >Expense List< /h1 >
    {props.expenses.map((expense) => {
      return < ExpenseListItem key={expense.id} {...expense}/ >
    })}
  < /div >
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q

What does map() allow?

A

To take in something and get back an array of something else. In our case we’re getting in an array of objects and trying to return an array of instances of ExpenseListItem.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q

What do you pass into map()

A

An updater function.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q

How would you implement the selector in this code?

const mapStateToProps = (state) => {
  return {
    expenses: state.expenses,
    filters: state.filters
  };
};
A

Here, we call selectExpenses() (with the necessary arguments) and render the return value.

const mapStateToProps = (state) => {
  return {
    expenses: selectExpenses(state.expenses, state.filters)
  };
};
58
Q

Start

A

103

59
Q

How would you create a presentational component that contains a text input?

A

NOTE: We implicitly return some JSX.

const ExpenseListFilters = () => (
  < div >
    < input type="text" / >
  < /div >
);
60
Q

How would you use ExpenseListFilters in ExpenseDashboardPage?

const ExpenseListFilters = () => (
  < div >
    < input type="text" / >
  < /div >
);
const ExpenseDashboardPage = () => (
  < div >
    < ExpenseList / >
  < /div >
);
A
const ExpenseDashboardPage = () => (
  < div >
    < ExpenseListFilters / >
    < ExpenseList / >
  < /div >
);
61
Q

How would connect ExpenseListFilters to the store?

const ExpenseListFilters = () => (
  < div >
    < input type="text" / >
  < /div >
);

export default ExpenseListFilters;

A

First, import connect. Then create a connected version of ExpenseListFilters.
NOTE: We get access to the entire state in mapStateToPtops via the first atgument.
NOTE: When you return the filters in mapStateToProps, ExpenseListFilters will have access to props.filters.text

const ExpenseListFilters = (props) => (
  < div >
    < input type="text" value={props.filters.text} / >
  < /div >
);
const mapStateToProps = (state) => {
  return {
    filters: state.filters
  };
};

export default connect(mapStateToProps)(ExpenseListFilters);

62
Q

How would you do something when the text value gets changed by the user?

const ExpenseListFilters = (props) => (
  < div >
    < input type="text" value={props.filters.text} / >
  < /div >
);
A

NOTE: The onChange function needs access to the store because the inputs value comes from the store via the text value.

const ExpenseListFilters = (props) => (
< div >
< input type=”text” value={props.filters.text} onChange={(e) => {
props.dispatch(// pass in the action object // setTextFIlter(e.target.value));
}} / >
< /div >
);

63
Q

What does onChange take?

A

A function and every time the input changes, the function fires.

64
Q

What does e give us access to in this code?

const ExpenseListFilters = (props) => (
< div >
< input type=”text” value={props.filters.text} onChange={(e) => {
props.dispatch(// pass in the action object // setTextFIlter(e.target.value));
}} / >
< /div >
);

A

The event argument.

65
Q

What happens when you connect a component to redux?

A

We get some other information passed into the component as well.

66
Q

What other information is passed into the component when you connect it to the redux store?

A

NOTE: This is in the react developer tools. Inside of switch, route, ExpenseDashboardPage there is a connected parent component and inside of it we have our component we created.

Here, we have to props. filters (which we expected because we provided it in mapStateToProps) and dispatch. dispatch is the same dispatch that we were accessing on the store. Therefore, we have access to dispatch from inside our connected components, meaning we can call it directly to dispatch actions.

67
Q

What would be involved in creating a remove button?

A

Create the button.
The button would dispatch an action when it gets clicked.
This means you’ll have to import the correct action generator (from the actionsExpenses file).
You’ll also have to connect the component to accessDispatch and lastly wire up onClick.
NOTE: You have access to id which you’ll need to remove the item.
NOTE: When you use connect, you don’t have to take anything from the state. eg
export default connect()(ExpenseListFilters)
This won’t give you any values form the state but it does give you access to dispatch.

68
Q

How would you wire up a button to remove an expense?

const ExpenseListItem = ({ description, amount, createdAt }) => (
  < div >
    < h3 >{description}< /h3 >
    < p >{amount} - {createdAt}< /p >
  < /div >
);

export default ExpenseListItem;

A

NOTE: This original code contained destructuring to get the props (description, amount, createdAt). You can add to this.
NOTE: removeExpense takes and object and id.
NOTE: We use the ES6 object definition shorthand.

const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < h3 >{description}< /h3 >
    < p >{amount} - {createdAt}< /p >
    < button onClick={() => {
      dispatch(removeExpense({ id }));
    }} >Remove< /button >
  < /div >
);

export default connect()(ExpenseListItem);

69
Q

NEXT

A

104

70
Q

How would you add a select option to this form.

const ExpenseListFilters = (props) => (
< div >
< input type=”text” value={props.filters.text} onChange={(e) => {
props.dispatch(setTextFIlter(e.target.value));
}} / >
< /div >
);

A

const ExpenseListFilters = (props) => (
< div >
< input type=”text” value={props.filters.text} onChange={(e) => {
props.dispatch(setTextFIlter(e.target.value));
}} / >
< select >
< option value=”date” >Date< /option >
< option value=”amount” >Amount< /option >
< /select >
< /div >
);

71
Q

How would you setup value and onChange in this code?

const ExpenseListFilters = (props) => (
< div >
< input type=”text” value={props.filters.text} onChange={(e) => {
props.dispatch(setTextFIlter(e.target.value));
}} / >
< select >
< option value=”date” >Date< /option >
< option value=”amount” >Amount< /option >
< /select >
< /div >
);

A
const ExpenseListFilters = (props) => (
  < div >
    < input type="text" value={props.filters.text} onChange={(e) => {
  props.dispatch(setTextFIlter(e.target.value));
}} / >
  < select
    value={props.filter.sortBy}
    onChange={(e) => {
      if (e.target.value === 'date') {
        props.dispatch(sortByDate());
      } else if (e.target.value === 'amount') {
        props.dispatch(sortByAmount());
      }
    }};
   >
    < option value="date" >Date< /option >
    < option value="amount" >Amount< /option >
  < /select >
  < /div >
);
72
Q

When we set up our form inputs (text inputs, select drop downs) and we use value and onChange, what are we creating?

A

A controlled input.

73
Q

What does the term controlled input mean?

A

An input where the value is controlled by JavaScript.

74
Q

Next

A

105

75
Q

How would you create a simple class based expense form for demonstration purposes?

A
export default const ExpenseForm extends React.Component {
  render() {
    return (
      < div >
        ExpenseForm
      < /div >
    )
  }
}
76
Q

How would you add the ExpenseForm component to this code?

const addExpensePage = () => (
  < div >
    < h1 >Add Expense< /h1 >
    This is form the add expense component
  < /div >
);
A
const addExpensePage = () => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm / >
  < /div >
);
77
Q

How would you set up the inputs, textarea and button for the ExpenseForm component?

export default const ExpenseForm extends React.Component {
  render() {
    return (
      < div >
        ExpenseForm
      < /div >
    )
  }
}
A
export default const ExpenseForm extends React.Component {
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
78
Q

NOTE: You only want to do something with the information when the user submits the form:
How would you use local component state to track the changes to all of the inputs on the ExpenseForm Component? (ie. We’ll keep track of the changes to every input, when they submit the form we’ll send it off to redux to either edit the existing expense or a new one).

export default const ExpenseForm extends React.Component {
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A
  1. Set the value of the text input equal to the current state value. NOTE: (value={this.state.description}) creates a read only input, so you’ll need to set up onChange()
  2. Set up onChange.
  3. Define onDescriptionChange.
  4. use this.setState() and pass in the updater function, and implicitly return an object (so you have to wrap it in parentheses) and set description to the description variable (you can just use ES6 object shorthand).
export default const ExpenseForm extends React.Component {
  state = {
    description: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}

NOTE: To check that this is working you can edit the description input field and in the React developer tools the state should change.

79
Q

How would you complete the ExpenseForm component?
NOTE: You need to set up note state, onChange and value for textarea

export default const ExpenseForm extends React.Component {
  state = {
    description: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}

NOTE: This is correct when you can type text in text box and see the note state change to the same value.

A
  1. Create the default state for note
  2. Now use that value in the textarea.
  3. Define onChange
  4. Define onNoteChange to set up the state value.
  5. Set up the updater function in this.setState (this implicitly returns an object). NOTE: We set the note state equal to the value of the note variable.
export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form>
      < /div >
    )
  }
}
80
Q

Why should you avoid writing the second code snip it?

 onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };

onNoteChange = (e) => {
this.setState(() => ({ note: e.target.value }));
};

A

NOTE: When you change the description you get a huge error message.

The problem is that we are trying to use e.target.value in the (this.setState) callback which doesn’t run right away. NOTE: It does work if we pull it out first, but it doesn’t work if we try to use it in a callback. The error message says to use event.persist().

onNoteChange = (e) => {
e.persisit();
this.setState(() => ({ note: e.target.value }));
};

With the original code, e.target.value is just pulled off into its own variable.

81
Q

How would you use some conditional logic to make amount work correctly?

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="number"
            placeholder="Amount"
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A

Switch over from a type of number to a type of text and add our own validation code. Set up a default state for amount.
NOTE: We us regular expressions.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
82
Q

What benefits do you get when you set type to number?

A

You can’t type a number, however, you can add more than two number after a decimal point (which we don’t want).

83
Q

What is a good resource for creating regular expressions that provides test string?

A

regex101.com

84
Q

Break

A

106

85
Q

What two libraries will you need to use for createdAt to work?

A

momentjs (momentjs.com) and react-dates (google airbnb react-dates)

86
Q

What is momentjs?

A

A time library.

87
Q

What does momentjs do?

A

Makes it easy to work with, manipulate and format time.

88
Q

What is react-dates?

A

Includes some components that make it easier to drop a calendar picker into your application.

89
Q

How do you install momentjs and react-dates?

A

yarn add moment@2.18.1 react-dates@12.3.0 (12.7.0) react-addons-shallow-compare@15.6.0

90
Q

What does react-dates require?

A

A peer dependency (which we won’t be using directly but it is used internally by the react-dates library) called react-addons-shallow-compare

91
Q

What is the react-addons-shallow-compare library?

A

A simple utility function used by react-dates. It’s currently no longer supported, but react-dates hasn’t changed there code to not rely on it.

92
Q

How would you import momentjs?

A

import moment from ‘moment’;

93
Q

How would you use momentjs in a basic way?

A

const now = moment();

94
Q

Why would you use momentjs over the Date() function?

A

Because the Date() API is difficult to use.

95
Q

What would you get back from this code?

const now = moment();

A

An instance of moment. If you don’t provide any arguments it represents the current point in time.

96
Q

How would you log the date of this code in the console?

const now = moment();

A

console.log(now.format(‘MMM Do, YYYY’));

97
Q

How can you view all the methods of moment?

A

log a moment to the console and go into the __proto__ chain.

98
Q

How would you import the react-dates library?

A

import { SingleDatePicker } from ‘react-dates’;

99
Q

What do you also have to import along with SingleDatePicker?

A

The CSS that’s related to it.

100
Q

How would you import the CSS that’s related with SingleDatePicker?

A

import ‘react-dates/lib/css/_datepicker.css’;

101
Q

What for props must be used for SingleDatePicker?

A

date
onDateChange (a handler for when the user picks a new date)
focus
onFocusChange (a handler for when the react-dates llbrary needs to change that value)

102
Q

How would you set up the necessary SingleDatePicker props?

A
Set CreatedAt (and others) in the state object.
NOTE: You have to define the onDateChange and onFocusChange handler. The object will be implicitly returned.

OnFocusChange: The first argumetn is an object. We’re destructuring it and grabbing the focused property and then setting on the state.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    this.setState(() => ({ createdAt }));
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
103
Q

What is the date?

A

A moment object that represents where you want to start.

104
Q

What is the prop onState change going to be?

A

A function we create. It’ll get called with a moment instance, when someone picks a new day from the calendar. Therefore, we set up a handler.

105
Q

How would you configure this code to only show one month at a time?

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    this.setState(() => ({ createdAt }));
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A
export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    this.setState(() => ({ createdAt }));
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
106
Q

How would you configure this code so you can pick days from the past?

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    this.setState(() => ({ createdAt }));
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A

Use isOutsideRange.
NOTE: isOutsideRange takes a function which we define inline.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    this.setState(() => ({ createdAt }));
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
107
Q

How can you watch the data change with regards to the date picker?

A

Go over to the React developer tools, search for the component (ExpenseForm) and on the right hand side you’ll see the state, which contains the moment object. Clicking this open, you can see the raw date which will change in real time if you click a new date on the date picker.

108
Q

sdf

A

107

109
Q

How would you update the regular expression to allow the user to clear the input filed.

if (amount.match(/REGEX/)) {
this.setState(() => ({ amount }));
}

A

if (!amount || amount.match(/REGEX/)) {
this.setState(() => ({ amount }));
}

110
Q

How would you prevent the user from being able to delete the date in the calendar picker?

onDateChange = (createdAt) => {
this.setState(() => ({ createdAt }));
};

A

Here, onDateChange gets called with the date if one was picked. If it was cleared, it’s going to get called with nothing. If we add an if statement, we can check if there’s a value.

onDateChange = (createdAt) => {
  if (createdAt) {
    this.setState(() => ({ createdAt }));
  }
};

This code says, if there is a createdAt value, use this.setState(). If there’s not, do nothing.

111
Q

How would you prevent the form from refreshing the whole page on submit?

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  render() {
    return (
      < div >
        < form >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A

NOTE: You must create an onSubmit handler.
NOTE: For forms, we do want to access e because we need to call e.preventDefault(); otherwise the browser is going to go through that full page refresh.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  onSubmit = (e) => {
    e.preventDefault();
  };
  render() {
    return (
      < div >
        < form onSubmit={this.onSubmit} >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
112
Q

How would you add validation to the onSubmit event handler?
NOTE: The only thing were concerned about is whether there’s a value for the description and amount fields. We don’t care what the format for description is, if there’s a value for amount we already know it’s in the correct format (because of the regular expression), the user can’t clear the date and the note field is optional.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  onSubmit = (e) => {
    e.preventDefault();
  };
  render() {
    return (
      < div >
        < form onSubmit={this.onSubmit} >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
A

You’ll need to set up an error state.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  onSubmit = (e) => {
    e.preventDefault();
    if (!this.state.description || !this.state.amount) {
      this.setState(() => ({ error: 'Please provide description and amount' }));
    } else {
      this.setState(() => ({ error: '' }));
    }
  };
  render() {
    return (
      < div >
        {this.state.error &amp;&amp; < p >{this.state.error}< /p >}
        < form onSubmit={this.onSubmit} >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
113
Q

NOTE: How would you dispatch an action (where is it going to happen)? It’s not going to happen in the component we just finished because the whole goal of expense forum is to be reused in AddExpensePage and the EditExpensePage. At the end of the day, if we’re adding or editing we need to dispatch different stuff. So we’re going to pass the data up, this will allow us to determine what to do with the data when the user submits the form on a dynamic basis.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  onSubmit = (e) => {
    e.preventDefault();
    if (!this.state.description || !this.state.amount) {
      this.setState(() => ({ error: 'Please provide description and amount' }));
    } else {
      this.setState(() => ({ error: '' }));
    }
  };
  render() {
    return (
      < div >
        {this.state.error &amp;&amp; < p >{this.state.error}< /p >}
        < form onSubmit={this.onSubmit} >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
const addExpensePage = () => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm / >
  < /div >
);
A

NOTE: onSubmit calls its function when the form is submitted with valid data and we get that data back, in this case we would get the expense object (expense) back, with all of the properties we would expect (description, amount, note and createdAt).
NOTE: description gets its value directly from this.state.description. It’s directly from because we’re not doing any parsing unlike amount (because it’s not in the format we want (it’s a string)).
NOTE: createdAt will require parsing as well as it’s not the timestamp we expect but a moment object instead.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };
  onDescriptionChange = (e) => {
    // we need access to the argument as this is where the value lives (hence e)
    const description = e.target.value;
    this.setState(() => ({ description }));
  };
  onNoteChange = (e) => {
    const note = e.target.value;
    this.setState(() => ({ note }));
  };
  onAmountChange = (e) => {
    const amount = e.target.value;
    if (amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onDateChange = (createdAt) => {
    if (!amount || amount.match(/REGEX/)) {
      this.setState(() => ({ amount }));
    }
  };
  onFocusChage = ({ focused }) => {
    this.setState(() => ({ calendarFocsed: fucused }))
  };
  onSubmit = (e) => {
    e.preventDefault();
    if (!this.state.description || !this.state.amount) {
      this.setState(() => ({ error: 'Please provide description and amount' }));
    } else {
      this.setState(() => ({ error: '' }));
      this.props.onSubmit({
        //this is called with data (an object with those properites defined in ExpenseForm?) 
        description: this.state.description,
        amount: parseFloat(this.state.amount, 10) * 100,
        createdAt: this.state.createdAt.valueOf(),
       note: this.state.note
      });
    }
  };
  render() {
    return (
      < div >
        {this.state.error &amp;&amp; < p >{this.state.error}< /p >}
        < form onSubmit={this.onSubmit} >
          < input
            type="text"
            placeholder="Description"
            autoFocus
            value={this.state.description}
            onChange={this.onDescriptionChange}
          / >
          < input
            type="text"
            placeholder="Amount",
            value={this.state.amount},
            onChange(this.onAmountChange)
          / >
         < SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          / >
          < textarea
            placeholder="Add a note (optional)"
            value={this.state.note}
            onChange={this.onNoteChange}
           >    
          < /textarea >
          < button >
            Add Expense
          < /button >
        < /form >
      < /div >
    )
  }
}
const addExpensePage = () => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm 
      onSubmit={(expense) => {
        console.log(expense);
      }}
    / >
  < /div >
);
114
Q

How would you get addExpensePage to dispatch the given action to the redux store, instead of logging the object to the console?

const addExpensePage = () => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm 
      onSubmit={(expense) => {
        console.log(expense);
      }}
    / >
  < /div >
);

export default AddExpensePage;

A

NOTE: You’ll have to import the named export connect from react-redux (because we want to connect the component to the store so it can dispatch). You also have to import the addExpense action generator.

const addExpensePage = (props) => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm 
      onSubmit={(expense) => {
        // Here, we're trying to dispatch an action
        props.dispatch(addExpense(expense));
      }}
    / >
  < /div >
);

NOTE: We don’t need anything from the state so we can leave the first parentheses empty, but we do need to pass the component into the second one. Now we have access to props.dispatch. You can access that by putting props in the addExpensePage argument.

export default connect()(AddExpensePage);

115
Q

How would you automate the redirect in this code?

const addExpensePage = (props) => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm 
      onSubmit={(expense) => {
        // Here, we're trying to dispatch an action
        props.dispatch(addExpense(expense));
      }}
    / >
  < /div >
);
A

NOTE: The component you render inside of react-router gets access to a bunch of special props. To prove it you can look at the react dev tools. Look for the addExpensePage component, click on it and you can see you have things passed in. We’re going to use on of the history methods.

const addExpensePage = (props) => (
  < div >
    < h1 >Add Expense< /h1 >
    < ExpenseForm 
      onSubmit={(expense) => {
        props.dispatch(addExpense(expense));
        props.history.push('/');
      }}
    / >
  < /div >
);

NOTE: This is going to switch over as if the Dashboard was clicked, which means we’re not going to go through the full page refresh.

116
Q

next

A

108

117
Q

How would you complete this?

const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      Editing the expense with the id of {props.match.params.id}
    < /div >
  );
};

DID I MISS THIS VIDEO? I HAD NO PRIOR CODE.

const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < h3 >{description}< /h3 >
    < p >{amount} - {createdAt}< /p >
    < button onClick={() => {
      dispatch(removeExpense({ id }));
    }} >Remove< /button >
  < /div >
);

NOTE: You’d have to make a small change to this code

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };.........
A

The only real difference between the AddExpensePage and the EditExpensePage is that the AddExpensePage is fine with empty defaults. The EditExpensePage wants to be able to provide the current values for that expense. To accomplish this we must pass in a single prop that gets passed into ExpenseForm (that’s optional). If it exists we’ll use the values from that expense as the default ones, if not we’ll stick to the the old code values.

  1. link over to the EditExpensePage with the correct id. (NOTE: You have to import link from react-router-dom).
const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < Link to={`/edit/${id}`} >
      < h3 >{description}< /h3 >
    < /Link >
    < p >{amount} - {createdAt}< /p >
    < button onClick={() => {
      dispatch(removeExpense({ id }));
    }} >Remove< /button >
  < /div >
);
export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };.........

CLEAN THIS UP NOT ALL CODE WAS CHANGES.

118
Q

How would you fill this page out? Connect EditExpensePage to the redux store.

const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      Editing the expense with the id of {props.match.params.id}
    < /div >
  );
};

export default EditExpensePage;

const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < Link to={`/edit/${id}`} >
      < h3 >{description}< /h3 >
    < /Link >
    < p >{amount} - {createdAt}< /p >
    < button onClick={() => {
      dispatch(removeExpense({ id }));
    }} >Remove< /button >
  < /div >
);
export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };.........
A

NOTE: We have the id but that’s not enough. We want to be able to get the entire expense object.

  1. Import connect
  2. Seatch the ecpenses array with an id that matches {props.match.params.id}
const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      Editing the expense with the id of {props.match.params.id}
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    //Here, we use the current props to search the expense array.
    expense: state.expenses.find((expense) => {
      return expense.id === props.match.params.id;
    })
  };
};

NOTE: We have an expression getting returned so we can use the arrow function shorthand

const mapStateToProps = (state, props) => {
  return {
    //Here, we use the current props to search the expense array.
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};

NOTE: We have access to state which is great because that’s where the expenses array lives, and we’re going to search it, but what are we searching for? For an expense that id matches this prop {props.match.params.id}. But how do we access it? We have access to the props as the second argument (next to state in the arguments).
Now we can take some of the current props that were passed into the current HOC and we can use them to calculate the props that we want to add on. Therefore, react router renders our HOC (export default connect()(EditExpensePage); (is this the HOC?)), the HOC passes the props through and also allows us to add on some new ones which is what we do with mapStateToProps.

export default connect(mapStateToProps)(EditExpensePage);
NOTE: This time we do want to set up a mapStateToProps function. We want to be able to give the component the current expense object.

NOTE: find allows us to search through an array looking for a single item. We determine whether or not we found the correct item by returning true from the callback.

119
Q

Now you have the expense accessible to use (as shown in the console.log call), How would you render the ExpenseForm in the EditExpensePage?

const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      Editing the expense with the id of {props.match.params.id}
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    //Here, we use the current props to search the expense array.
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};
export default connect(mapStateToProps)(EditExpensePage);
A

NOTE: In EditExpensePage.js you must import ExpenseForm.

const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      < ExpenseForm
        onSubmit={(expense) => {
          console.log('updated', expense);
        }}
      / >
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    //Here, we use the current props to search the expense array.
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};
export default connect(mapStateToProps)(EditExpensePage);
120
Q

How would you get the data to populate with the corrrect values when you visit that route?

const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      < ExpenseForm
        onSubmit={(expense) => {
          console.log('updated', expense);
        }}
      / >
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};

export default connect(mapStateToProps)(EditExpensePage);

A
const EditExpensePage = (props) => {
  console.log(props);
  return (
    < div >
      < ExpenseForm
        //here, we define a new prop on ExpenseForm. It's an existing expense. We have access to it on {props.expense} (which we just proved via the console.log)
        expense={props.expense}
        onSubmit={(expense) => {
          console.log('updated', expense);
        }}
      / >
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};

export default connect(mapStateToProps)(EditExpensePage);

121
Q

How would you set up ExpenseForm to do something meaningful with this new prop {props.expense} that it’s getting?

ie this goal is to take the top four state values (description, note, amount and createdAt) and only use the defaults if no expense was passed down (that’s going to make sure the AddExpensePage still works). But if an expense was passed down, we want to start them off at there values.

export default const ExpenseForm extends React.Component {
  state = {
    description: '',
    note: '',
    amount: '',
    createdAt: moment(),
    calendarFocused: false,
    error: ''
  };.........
const EditExpensePage = (props) => {
  return (
    < div >
      < ExpenseForm
        expense={props.expense}
        onSubmit={(expense) => {
          console.log('updated', expense);
        }}
      / >
    < /div >
  );
};
const mapStateToProps = (state, props) => {
  return {
    expense: state.expenses.find((expense) => expense.id === props.match.params.id)
  };
};

export default connect(mapStateToProps)(EditExpensePage);

A

NOTE: We get that done by looking at the props. We can’t do that in the normal syntax. We have to define out state in the constructor function to access the props.

constructor(props) {
super(props);
this.state = {
description: props.expense ? props.expense.description : ‘’,
note: props.expense ? props.expense.note : ‘’,
amount: props.expense ? (props.expense.amount / 100).toString() : ‘’,
createdAt: props.expense ? moment(props.expense.createdAt) : moment(),
calendarFocused: false,
error: ‘’
}
}

122
Q

How would you dispatch this code?

const EditExpensePage = (props) => {
  return (
    < div >
      < ExpenseForm
        expense={props.expense}
        onSubmit={(expense) => {
          // dispatch the action to edit the expense
          // Redirect to the dashboard 
          console.log('updated', expense);
        }}
      / >
    < /div >
  );
};
A
  1. import the editExpense action.
    NOTE: Instead of using props.expense.id you could use match.paras.id
const EditExpensePage = (props) => {
  return (
    < div >
      < ExpenseForm
        expense={props.expense}
        onSubmit={(expense) => {
          props..dispatch(editExpense(props.expense.id, expense));
Here, we're taking expense and passing it in.
          props.history.push('/');
        }}
      / >
    < /div >
  );
};
123
Q

How would you take the remove button (which currently lives in ExpenseListItem), get rid of it from this component and put it in the EditExpencePage.

i.e. Remove expense via dispatch and then redirect to dashboard

const EditExpensePage = (props) => {
  return (
    < div >
      < ExpenseForm
        expense={props.expense}
        onSubmit={(expense) => {
          props..dispatch(editExpense(props.expense.id, expense));
Here, we're taking expense and passing it in.
          props.history.push('/');
        }}
      / >
    < /div >
  );
};
const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < Link to={`/edit/${id}`} >
      < h3 >{description}< /h3 >
    < /Link >
    < p >{amount} - {createdAt}< /p >
    < button onClick={() => {
      dispatch(removeExpense({ id }));
    }} >Remove< /button >
  < /div >
);

export default connect()(ExpenseListItem);

A

NOTE: When you remove it from ExpenseListItem you can also get ride of of connect()().
Also, you have to grab the import for removeExpense

const EditExpensePage = (props) => {
  return (
    < div >
      < ExpenseForm
        expense={props.expense}
        onSubmit={(expense) => {
          props..dispatch(editExpense(props.expense.id, expense));
Here, we're taking expense and passing it in.
          props.history.push('/');
        }}
      / >
    < button onClick={() => {
      props.dispatch(removeExpense({ id: props.expense.id }));
      props.history.push('/');
    }} >Remove< /button >
    < /div >
  );
};
//NOTE: dispatch can be removed.
const ExpenseListItem = ({ dispatch, id, description, amount, createdAt }) => (
  < div >
    < Link to={`/edit/${id}`} >
      < h3 >{description}< /h3 >
    < /Link >
    < p >{amount} - {createdAt}< /p >

< /div >
);

export default ExpenseListItem;

124
Q

next

A

106

125
Q

What does the redux developer tools allow for?

A

view the store.
view the actions.
the data and data changes.

126
Q

How do you set the redux dev tools

A

Google redux development tools extension.

127
Q

What do you have to do to use the redux dev tools?

A

Install the extensions

change the code a little. We need to make a change on how we’re using createStore()

128
Q

How do you set up redux dev tools?

A

NOTE: this line changes over time so it’s recommented to get it from the site itselg.

copy the line (not the plus sign), go to configureStore.js and pass the argument in as the second line to create store.

129
Q

Why do you have to setpup redux dev tools?

A

THis allows the redux dev tools to connect to the store.

130
Q

What do we get whe the redux dev tools are setup correctly?

A

A tonne of information.
the redux dev tools are more complex than the react dev tools.
ON the left hand side we see a list of all of the actions that were dispatched with the most recent ones up top. @@INIT action is when our redux store has the default values set. When we click them we can dive a little deeper. We can look at the action object itself. We can look at the state. We can also look at just the differences.

What’s most useful is to view the application state. So you can click on the last action, go to state, and you can see the data you’re currecntly working with. This can help us varify what were seeing on the screen is correct and it’s correct for the right reasons.

As you interact with the application we’re going to see changes down below.

We also have the ability to dispatch something in line. Maybe not used much.

The slider allows you to view your application state over time. This will actially change what’s up above.

131
Q

asas

A

as

132
Q

as

A

as

133
Q

as

A

as

134
Q

as

A

as

135
Q

as

A

as

136
Q

as

A

as

137
Q

as

A

as

138
Q

as

A

as

139
Q

now

A

110

140
Q

theses one more video

A

s