Udemy - Redux Flashcards

1
Q

What is Redux?

A

A library that makes it possible to manage more complex state.

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

What is the Redux store?

A

An object.

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

Give an example of a Redux store:

A
{
  expenses: [{
    _id: 'abc',
    description: 'rent',
    amount: 109500
  }]
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What are the shortcomings of using component state?

A

In complex apps, there may be no clear parent component where we can store the state.
Components aren’t reusable if they need things from the parent.

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

What two things can each component define in Redux?

A

What data it needs.

What data it needs to be able to change.

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

How do you install Redux?

A

yarn add redux@x

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

What’s the first thing you do in Redux?

A

Import the createStore function.

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

How would you import the store function from Redux?

A

import { createStore } from ‘redux’;

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

How many times would you call createStore?

A

Once.

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

How would you create a store?

A
const store = createStore((state = { count: 0 }) => {
  return state;
});
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Can you call createStore without any arguments?

A

No.

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

What is the first argument createStore expects?

A

A function (state).

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

What does state mean in this code?

const store = createStore((state) => {
  return state;
});
A

The current state.

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

What does state = { count: 0 } mean in this code?

const store = createStore((state = { count: 0 }) => {
  return state;
});
A

Because we don’t have a constructor function where we set up the default we set it up here.

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

What does the store.getState() method do?

A

Returns the current state object.

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

How could you view the state object in this code in the console?

const store = createStore((state = { count: 0 }) => {
  return state;
});
A

console.log(store.getState());

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

What do actions allow us to do?

A

Change the Redux store.

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

What is an action?

A

An object that gets sent to the store. This object describes the type of action we’d like to take.

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

How do you create an action?

A

Define an object, with a type property.

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

What is the single property you have to define on an action?

A

The type property.

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

What Redux convention does the action objects type property value use?

A

Written in all upper case with an underscore to separate multiple words.

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

What do you do after you define a type property on an action object?

A

Send it to the store.

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

How would you send an action to the store.

A

By calling a method on store called store.dispatch();

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

What does dispatch allow us to do?

A

Send off an action object.

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

How would you use store.dispatch() with an action.

A

Put the action object in the dispatch method.

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

Show an example of using store.dispatch() with an action.

A

store.dispatch({
type: ‘INCREMENT’
});

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

What happens to the store when using this code?

store.dispatch({
type: ‘INCREMENT’
});

A

The createStore function runs again.

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

How can you verify that store.dispatch is calling the createStore function again?

A

Log a comment in the createStore function body.

const store = createStore((state = { count: 0 }) => {
  console.log('running');
  return state;
});
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

How does the store get access to the action object?

A

It gets passed in as the second argument to createStore function.

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

Show how you would write the createStore function to have access to the action object:

A
const store = createStore((state = { count: 0 }, action) => {
  console.log('running');
  return state;
});
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

Is it a good idea to pass in a default action as the second parameter to the createStore function?

A

No, because the action will get passed in.

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

What can we do when the createStore function has access to action?

A

We can combine the current action with the state to figure out what the new state should be.

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

How could you use action in the createStore function?

A

You could use an if statement to check the ‘type’ of action and then do something.

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

Show a simple example of what the createStore functions body would look like if you wanted to increment a count:

A
if (action.type === 'INCREMENT') {
  return {
    count: state.count + 1
  };
} else {
  return state;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

What is noteworthy about ‘count: state.count + 1’?

if (action.type === 'INCREMENT') {
  return {
    count: state.count + 1
  };
} else {
  return state;
}
A

The state isn’t changed. It’s not a good idea to change the state or the action. Instead you want to use those values to compute the new state, that’s what gets returned.

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

How would you convert this if statement to a switch statement?

if (action.type === 'INCREMENT') {
  return {
    count: state.count + 1
  };
} else {
  return state;
}
A
switch (action.type) {
  case 'INCREMENT': 
    return {
      count: state.count + 1
    };
  default: 
    return state;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

Does store.getState() rerun when the store changes?

A

No.

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

Why do we need to be able to know when the store changes?

A

So we can re-render our application.

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

How can you watch for changes to the Redux store state?

A

You can use store.subscribe()

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

What is store.subscribe()

A

A function.

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

What do you pass to store.subscribe()

A

A single function.

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

What’s not worthy about the function you pass to store.subscribe()

A

It get called every time the store changes.

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

Show a simple example of using store.subscribe()

A

store.subscribe(() => {
console.log(store.getState());
});

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

What does this code do?

store.subscribe(() => {
console.log(store.getState());
});

A

Logging the state to the console every time it changes.

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

How would you stop subscribing to the store?

A

Call the return value of subscribe (a function).

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

What is something you would have to do to store.subscribe() before you can call its return value?

A

Save it as a variable.

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

Show a simple example of how you would unsubscribe from the store:

A
const unsubscribe = store.subscribe(() => {
  console.log(store.getState());
});

unsubscribe();

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

What will happen if you have an undefined type property in an action?

A

It will throw an error.

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

How would you use ‘incrementBy’, which may or may not be present, in the store?

store.dispatch({
type: ‘INCREMENT’,
incrementBy: 5
});

A

You would use some conditional logic, specifically the ternary operator.

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

Show how you would you use ‘incrementBy’, which may or may not be present, in the store?

store.dispatch({
type: ‘INCREMENT’,
incrementBy: 5
});

A
switch (action.type) {
  case 'INCREMENT':
    const incrementBy = typeof action.incrementBy === 'number' ? action.incrementBy : 1; 
    return {
      count: state.count + incrementBy
    };
  default: 
    return state;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

How can you use action that have require types?

A

By using them directly as opposed to checking if they exist.

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

Give an example of how you would handle this action in the store:

store.dispatch({
type: ‘SET’,
count: 101
});

A
switch (action.type) {
  case 'SET':
    return {
      count: action.count
    };
  default: 
    return state;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q

What does ES6 Object Destructuring allow us to do?

A

Easily work with arrays and objects.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q
const person = {
  name: 'Chris',
  age: 32,
  location: {
    town: 'Barry',
    temp: 20
  }
}

How could you use object destructuring to improve the following line of code?

console.log(${person.name} is ${person.age}.);

A

const { name, age } = person;

console.log(${name} is ${age}.);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q
const person = {
  name: 'Chris',
  age: 32,
  location: {
    town: 'Barry',
    temp: 20
  }
}

How could you use object destructuring to improve the following line of code?

if (person.location.town && person.location.temp) {
console.log(It's ${person.location.temp} in ${person.location.town}.);
};

A

const { town, temp } = person.location;

if (town && temp) {
console.log(It's ${temp} in ${town}.);
};

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

What could go wrong in this code?

if (person.location.town && person.location.temp) {
console.log(It's ${person.location.temp} in ${person.location.town}.);
};

A

A temp of 0 would result in fasly. You could use typeof to fix that.

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

How would you rename ‘temp’ in this destructued object?

const { town, temp } = person.location;

A

const { town, temp: temperature } = person.location;

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

How would you set up a default value in this destructued object?

const { name, age } = person;

A

const { name = ‘Anonymous’, age } = person;

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

How would you set up both a default value and rename it in this destructured object?

const { name, age } = person;

A

const { name: firstName = ‘Anonymous’, age } = person;

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

What is the problem with this code?

const address = ['’1299 S Street, ‘London’, ‘England’, ‘14430’];

console.log(You are in ${address[1]}, ${address[2]}.);

A

It’s not clear what address[1] is.

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

How would you use array destructuring here?

const address = ['’1299 S Street, ‘London’, ‘England’, ‘CF93 2LM’];

console.log(You are in ${address[1]}, ${address[2]}.);

A

const [, city, country] = address;

console.log(You are in ${city}, $country}.);

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

How would you set a default to this destructured array?

const [, city, country] = address;

A

const [, city, country = ‘UK’] = address;

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

What is an action generator?

A

A function that returns an action object.

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

What does an action generator mean for our code so far?

A

The objects that we have created via store.dispatch() will now be created in one place, and we’ll have a function we can call to generate the action objects.

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

What’s the first step in creating an action generator?

A

Creating a function.

const incrementCount = () => {

};

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

What’s the goal of an action generator.

A

To be a simple function that takes input in, and returns the new action object.

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

Show an action generator returning a new action object:

A
const incrementCount = () => {
  return {
    type: 'INCREMENT'
  };
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q

How could you improve this code?

const incrementCount = () => {
  return {
    type: 'INCREMENT'
  };
};
A

By implicitly returning the object.

const incrementCount = () => ({
  type: 'INCREMENT'
});
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q

What do you need to do when implicitly returning objects?

A

Wrap the object in parentheses.

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

How would you call this function?

const incrementCount = () => ({
  type: 'INCREMENT'
});
A

store.dispatch(incrementCount());

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

What’s one of the disadvantages of manually generating your objects like this?

store.dispatch({
type: ‘INCREMENT’,
incrementBy: 5
});

A

They’re susceptible to typos which aren’t easy to catch. You also get the advantage of auto completion by using action generators.

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

How would you set up this action generator to handle custom data that’s needed?

const incrementCount = () => ({
  type: 'INCREMENT'
});
A
const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: ...
});
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q

How would you dispatch an object with an incrementBy argument in this code?

store.dispatch(incrementCount());

A

store.dispatch(incrementCount({ incrementBy: 5 }));

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

What is happening with the payload argument here?

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT'
});
A

If payload doesn’t exist, it’s going to default to an empty object.

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

What do you need to consider when setting up ‘incrementBy’ in the function body?

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: ...
});
A

You have to set it up for every single instance of the action object, which means we’re going to come up with a default here as opposed to the createStore() function.

76
Q

Show how you would set up the defaults on incrementBy:

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: ...
});
A
const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});
77
Q

When you set up the default in the action generator what would you do to this code?

switch (action.type) {
  case 'INCREMENT':
    const incrementBy = typeof action.incrementBy === 'number' ? action.incrementBy : 1; 
    return {
      count: state.count + incrementBy
    };
  default: 
    return state;
}
A

Remove the const and access incrementBy from action, knowing it’s always going to be set and set correctly.

switch (action.type) {
  case 'INCREMENT':
    return {
      count: state.count + action.incrementBy
    };
  default: 
    return state;
}
78
Q

Why do you need the default here?

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT'
});
A

If you remove the default and you had a situation where you didn’t pass anything into incrementCount(), you would be trying to access a property (incrementBy) on an object (payload) that is undefined, which will throw a type error.

79
Q

What’s important to note about destructuring?

A

We can destructure on a full line or we can destructure arguments that get passed into functions.

80
Q

How would you set up add in this example?

console.log(add({ a: 1, b:12 }));

A
const add = (data) => {
  return data.a + data.b;
};
81
Q

How would you destructure this object?

const add = (data) => {
  return data.a + data.b;
};
A

Remove the name and use curly braces instead. Here, we are destructuring the first argument that gets passed into add. In this case, we know it’s going to be an object, so it’s valid to set this up.

const add = ({ a, b }) => {
  return a + b;
};

See: Refactoring and Organizing @ 8:31

82
Q

How would you set up another argument if you wanted to pass something else in?

console.log(add({ a: 1, b:12 }, c: 100));

const add = ({ a, b }) => {
  return a + b;
};
A
const add = ({ a, b }, c) => {
  return a + b + c;
};
83
Q

What’s the first thing you would do if you want to set up default values in this code?

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});
A

Replace payload with an object.

const incrementCount = ({} = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});

At this point, we’re not destructuring anything.

84
Q

What do we want to destructure in this example?

const incrementCount = ({} = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});
A

incrementBy.

85
Q

Destructure incrementBy in this code:

const incrementCount = ({} = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});
A
const incrementCount = ({ incrementBy } = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof incrementBy === 'number' ? incrementBy : 1
});
86
Q

What does destructuring do here?

const incrementCount = ({ incrementBy } = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof incrementBy === 'number' ? incrementBy : 1
});
A

It gives us access to the incrementBy value off of the first object, so we can access it directly, hence deleting the payload object.

87
Q

How can we take destructuring one step further here?

const incrementCount = ({ incrementBy } = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof incrementBy === 'number' ? incrementBy : 1
});
A

We can set up the default value in the …

const incrementCount = ({ incrementBy = 1 } = {}) => ({
  type: 'INCREMENT',
  incrementBy: incrementBy
});
88
Q

How can we simplify this code?

const incrementCount = ({ incrementBy = 1 } = {}) => ({
  type: 'INCREMENT',
  incrementBy: incrementBy
});
A

When we’re setting an object property equal to a variable name with the same name we can do this:

const incrementCount = ({ incrementBy = 1 } = {}) => ({
  type: 'INCREMENT',
  incrementBy
});
89
Q

What can this be simplified as?

const incrementCount = (payload = {}) => ({
  type: 'INCREMENT',
  incrementBy: typeof payload.incrementBy === 'number' ? payload.incrementBy : 1
});
A
const incrementCount = ({ incrementBy = 1 } = {}) => ({
  type: 'INCREMENT',
  incrementBy
});
90
Q

How would the ‘1’ get set in this code?

const incrementCount = ({ incrementBy = 1 } = {}) => ({
  type: 'INCREMENT',
  incrementBy
});
A

It’s going to get set equal to 1 if there’s an object provided and it doesn’t include ‘incrementBy’. If there is no object provided, the default is going to be an empty object. When we try to destructure that empty object we’re not going to have incrementBy, so the end result is 1.

See: Refactoring and Organizing 16:41.

91
Q

What’s the next step in creating an action generator here?

const decrementCount = () => ({
  type: 'INCREMENT'
});
A

Destructure the argument that gets passed in and then if it doesn’t exist, start it off as an empty object.

const decrementCount = ({decrementBy = 1} = {}) => ({
  type: 'INCREMENT',
  decrementBy
});

NOTE: if decrementBy doesn’t exist it will default to 1.

92
Q

What is the function inside the createStore method? called?

A

A reducer.

93
Q

What does the reducer do?

A

It determines what to do based off an action. How do we want to change the state.

94
Q

How would you convert this code to be it’s own reducer?

const store = createStore((state = { count: 0 }, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + action.incrementBy
      };
    case 'DECREMENT':
      return {
        count: state.count - action.decrementBy
      };
    case 'SET':
      return {
        count: action.count
      };
    case 'RESET':
      return {
        count: 0
      };
    default:
      return state;
  }
});
A

const store = createStore(countReducer);

const countReducer = (state = { count: 0 }, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + action.incrementBy
      };
    case 'DECREMENT':
      return {
        count: state.count - action.decrementBy
      };
    case 'SET':
      return {
        count: action.count
      };
    case 'RESET':
      return {
        count: 0
      };
    default:
      return state;
  }
}
95
Q

What are some key attributes of a reducer?

A

They are pure functions.
You never want to change state or action. Instead you should read things off them and return an object that represents the new state.

96
Q

What does combineReducers allow us to do?

A

Create multiple functions that define how our Redux application changes, and combine them together.

97
Q

Give an example of creating a static final state:

A
const demoState = {
  expenses = [{
    id: 'asdfsafsaff',
    description: 'yada yada',
    note: 'yada yada',
    amount: 54500,
    createdAt: 0
  }],
  filters: {
    text: 'rent',
    sortBy: 'amount', // date or amount
    startDate: undefined,
    endDate: underfined
  }
};
98
Q

How would you set up a more complex default state for the reducer?

A

Create a variable for the default value and reference the variable inline.

99
Q

Show how you would set up a more complex default state for the reducer?

A

const expensesReducerDefaultState = […];

const expensesReducer = (state = expensesReducerDefaultState, action) => {

};

100
Q

How would you complete this reducer to its most basic sense?

const expensesReducer = (state = expensesReducerDefaultState, action) => {

};

A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
101
Q

How could you take a look at what the (default?) state is?

A

const store = createStore(expensesReducer);

console.log(store.getState());

NOTE: This isn’t reactive (we haven’t put it in subscribe) so it’ll fire a single time.

102
Q

How would you get the default array to live on the expenses property?

A

We need to change the call to createStore()

const store = createStore(expensesReducer);

const store = createStore(
  combineReducers({
    expenses: expensesReducer
  })
);

NOTE: If you were logging the (default) state to the store, it would change from [], to Object {expenses: Array(0)}. Now the redux store is an object, with a property expenses which is where the array lives.

NOTE: The goals of this was to get the array moved off of the actual store itself and into a property (in this case expenses on the root object).

103
Q

What does combineReducers() function do?

A

Lets you combine multiple reducers to create a single store.

104
Q

What argument does combineReducers() take?

A

An object. On the object we provide key value pairs. The key is the root state name (eg. expenses, filters) and the value is the reducer that’s supposed to manage it (eg. expensesReducer).

105
Q

Why, when you use this code does logging the state to the console look different?

const store = createStore(expensesReducer);

vs.

const store = createStore(
  combineReducers({
    expenses: expensesReducer
  })
);
A

Previously, we took expensesReducer and we passed that directly into create store. createStore called out reducer (it calls the reducer once right away) with no state and no action. So the end result was the default state getting set and then there was no action type. As there was no action type we had the state returned, and the empty array became the redux store value. We’re doing the same thing with combineReducers accept we’re saying why don’t we create an object like this ({ expenses: expensesReducer }) and put the array on the expenses property.

SEE: Working with Multiple Reducers 7:33

106
Q

sdf

A

zssf

107
Q

sdfasf

A

asdfasf

108
Q

asdfsafd

A

sdfasf

109
Q

asdfsafd

A

asdfsadf

110
Q

asdfsadf

A

asdfasdf

111
Q

Show an example of setting up an object as a default state:

A
const filtersReducerDefaultState = {
  text: '',
  sortBy: 'date',
  startDate: undefined,
  endDate: underfined
};
112
Q

Create a reducer that uses this default state:

const filtersReducerDefaultState = {
  text: '',
  sortBy: 'date',
  startDate: undefined,
  endDate: underfined
};
A
const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
113
Q

How would you register a second reducer on combineReducers()?

A
const store = createStore(
  combineReducers({
    expenses: expensesReducer,
    filters: filtersReducer
  })
);
114
Q

What does the ES6 spread operator allow in Redux?

A

It makes it easier to work with arrays and objects.

115
Q

Write a simple action generator:

A
const addExpense = (
  {
    description = '', 
    note = '', 
    amount = 0, 
    createdAt = 0} = {}
) => ({
  type: 'ADD_EXPENSE',
  expense: {
    id: uuid(),
    description,
    note,
    amount,
    createdAt
  }
});

NOTE: We’re implicitly returning the action object.
NOTE: We’re using destructuring (Which has been broken up on different lines to make it more readable).
NOTE: We’re using property shorthand.

116
Q

How could you create unique id’s?

A

By using the npm library, uuid (universally unique identifiers).

117
Q

How would you install uuid?

A

yarn add uuid@x

118
Q

How would you import uuid?

A

import uuid from ‘uuid’;

119
Q

How would you call uuid?

A

uuid()

120
Q

How would you call this action generator?

const addExpense = (
  {
    description = '', 
    note = '', 
    amount = 0, 
    createdAt = 0} = {}
) => ({
  type: 'ADD_EXPENSE',
  expense: {
    id: uuid(),
    description,
    note,
    amount,
    createdAt
  }
});

store.subscribe(() => {
console.log(store.getState());
});

A

Below where the store gets defined:

store.dispatch(addExpense({
description: ‘Rent’,
amount: 54500
}));

NOTE: We don’t have to provide all the values outlined.

The dispatched action (the action with the type ‘ADD_EXPENSE’) is going to get dispatched to both reducers (expensesReducer, filtersReducer).

121
Q

93.

How would you set up the expensesReducer to handle dispatching an action?

const expensesReducerDefaultState = […];

const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return state.concat(action.expense);
    default:
      return state;
  }
};

NOTE: As we know state is an array we might be tempted to use state.push(action.expense) to manipulate the array. The problem with this is that .push changes the original array.

122
Q

How would you convert .concat to use the ES6 spread operator functionality?

const names = [‘Bill’, ‘Ben’];

names.concat(‘John’);

A

[…names, ‘John’]

123
Q

How would you convert this code to use the ES6 spread operator functionality?

const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return state.concat(action.expense);
    default:
      return state;
  }
};
A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    default:
      return state;
  }
};
124
Q

What’s noteworthy when dispatching something?

A

You get the action object from store.dispatch(); This means if you dispatch an cation object, it comes back as the return value from the call to dispatch and we could create a variable to store it.

125
Q

How would you create a variable that stores the action object from store.dispatch()

A
const expenseOne = store.dispatch(addExpense({
  description: 'Rent',
  amount: 54500
}));
const expenseTwo = store.dispatch(addExpense({
  description: 'Coffee',
  amount: 500
}));
126
Q

What does this variable equal?

const expenseOne = store.dispatch(addExpense({
  description: 'Rent',
  amount: 54500
}));
A

The action object.

127
Q

How would you write the function call to delete an entry?

A

Here, we dispatch an action object that comes back from removeExpense:

store.dispatch(removeExpense({
id: expenseOne.expense.id
}));

128
Q

How would you create the removeExpense action generator?

A

NOTE: Here, we’re implicitly returning an object.
NOTE: We’re using destructuring.

const removeExpense = ({ id } = {}) => ({
  type: 'REMOVE_EXPENSE',
  id
});
129
Q

How would you handle removeExpense on the expensesReducer?

const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    default:
      return state;
  }
};
A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    case 'REMOVE_EXPENSE':
      return state.filter(({ id }) => { 
        return id !== action.id;
      });
    default:
      return state;
  }
};

NOTE: if the function passed into .filter return as true the item will be kept in the array, it it returns false the item will be removed.

NOTE: the individual item could’ve been called something like expense, however, we destructureing the expense and getting id.

130
Q

What is noteworthy about .filter

A

.filter doesn’t change the array its called on, and returns a new array with the subset of the values.

131
Q

How could you simplify this code?

const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    case 'REMOVE_EXPENSE':
      return state.filter(({ id }) => { 
        return id !== action.id;
      });
    default:
      return state;
  }
};
A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    case 'REMOVE_EXPENSE':
      return state.filter(({ id }) => id !== action.id);
    default:
      return state;
  }
};
132
Q

How would you add all of the properties from user to a new object?

const user = {
  name: 'John',
  age: 30
};
A

console.log({
…user
});

133
Q

What’s noteworthy about the ES6 object spread operator?

A

It’s not universally compatible with browsers.

134
Q

How can we get the ES6 object spread operator to work in all browsers?

A

By using a babel plugin.

135
Q

How would you install a babel plugin so we can use ES6 object spread operators universally?

A

yarn add babel-plugin-transform-object-rest-spread@?

136
Q

How would you include babel-plugin-transform-object-rest-spread in a project?

A

List it in the plugins array in .babelrc

“plugins”: [
“transform-object-rest-spread”
]

137
Q

How would you add properties on an object spread operator?

console.log({
…user
});

A

console.log({
…user,
location: ‘UK’
});

138
Q

How could you override existing properties using the object spread operator?

const user = {
  name: 'John',
  age: 30
};
A
console.log({
  ...user,
  location: 'UK',
  age: 31
});

NOTE: You must define extra properties after the spread operator.

139
Q

How would you use an editExpense function?

A

store.dispatch(editExpense(expenseTwo.expense.id, { amount: 500 }));

140
Q

What details do we need to give editExpense when dispatching?

A

The id of what we’re trying to edit and what we’re trying to edit, which will be the updates object.

141
Q

How would you create the action generator for editExpense?

A

NOTE: There’s no need for id or updates to have defaults.
NOTE: We’re implicitly returning an object.

const editExpense (id, updates) => ({
  type: 'EDIT_EXPENSE',
  id,
  updates
});
142
Q

How would you handle ‘EDIT_EXPENSE’?

const editExpense (id, updates) => ({
  type: 'EDIT_EXPENSE',
  id,
  updates
});
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    case 'REMOVE_EXPENSE':
      return state.filter(({ id }) => id !== action.id);
    default:
      return state;
  }
};
A
const expensesReducer  = (state = expensesReducerDefaultState, action) => {
  switch (action.type) {
    case 'ADD_EXPENSE':
      return [
        ...state
        action.expense
      ];
    case 'REMOVE_EXPENSE':
      return state.filter(({ id }) => id !== action.id);
    case 'EDIT_EXPENSE':
      return state.map((expense) => {
        if (expense.id === action.id) {
          return {
            ...expense,
            ...action.updates
          };
        } else {
          return expense;
        };
      })
    default:
      return state;
  }
};
143
Q

What does returning a call to state.map allow us?

A

To go through every item in an array?

144
Q

How would you call setTextFilter()

A

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

145
Q

How would you set up the setTextFilter() action object?

A

NOTE: If no ‘text’ value is provided, it will default to an empty string.
NOTE: We implicitly return an object

const setTextFilter = (text = '') => ({
  type: 'SET_TEXT_FILTER',
  text
});
146
Q

How would you add a case for setTextFilter() to the filters reducer?

const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
A

NOTE: We don’t have to mention this in the expenses reducer because the expenses reducers data isn’t going to change if the text filter changes.

const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    case 'SET_TEXT_FILTER':
      return {
        ...state,
        text: action.text
      };
    default:
      return state;
  }
};
147
Q

How would you dispatch sortByAmount()

A

store.dispatch(sortByAmount());

148
Q

How would you create the sortByAmount() action generator function?

A

NOTE: We’re implicitly returning an object here.

const sortByAmount = () => ({
  type: 'SORT_BY_AMOUNT'
});
149
Q

How would you dispatch sortByDate()

A

store.dispatch(sortByDate());

150
Q

How would you create the sortByDate() action generator function?

A

NOTE: We’re implicitly returning an object here.

const sortByDate = () => ({
  type: 'SORT_BY_DATE'
});
151
Q

How would you add the cases for sortByDate() and sortByAmount() in the filters reducer?

const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    case 'SET_TEXT_FILTER':
      return {
        ...state,
        text: action.text
      };
    default:
      return state;
  }
};
A
const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    case 'SET_TEXT_FILTER':
      return {
        ...state,
        text: action.text
      };
    case 'SORT_BY_AMOUNT':
      return {
        ...state,
        sortBy: 'amount'
      };
    case 'SORT_BY_DATE':
      return {
        ...state,
        sortBy: 'date'
      };
    default:
      return state;
  }
};
152
Q

How would you create the setStartDate() action generator function?

A

NOTE: There’s no need to set up a default of undefined for startDate because that’s the value by default.
NOTE: We implicitly return an object.

const setStartDate = (startDate) => ({
  type: 'SET_START_DATE',
  startDate
});
153
Q

How would you create the setEndDate() action generator function?

A

NOTE: There’s no need to set up a default of undefined for endDate because that’s the value by default.
NOTE: We implicitly return an object.

const setEndDate = (endDate) => ({
  type: 'SET_END_DATE',
  endDate
});
154
Q

How would you call setEndDate() with and without a value?

A

store. dispatch(setStartDate(125));

store. dispatch(setStartDate());

155
Q

How would you call setEndDate()

A

store.dispatch(setStartDate(1250));

156
Q

How would you add the cases for setStartDate() and setEndDate() in the filters reducer?

const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    case 'SET_TEXT_FILTER':
      return {
        ...state,
        text: action.text
      };
    case 'SORT_BY_AMOUNT':
      return {
        ...state,
        sortBy: 'amount'
      };
    case 'SORT_BY_DATE':
      return {
        ...state,
        sortBy: 'date'
      };
    default:
      return state;
  }
};
A
const filtersReducer = (state = filtersReducerDefaultState, action) => {
  switch (action.type) {
    case 'SET_TEXT_FILTER':
      return {
        ...state,
        text: action.text
      };
    case 'SORT_BY_AMOUNT':
      return {
        ...state,
        sortBy: 'amount'
      };
    case 'SORT_BY_DATE':
      return {
        ...state,
        sortBy: 'date'
       };
     case 'SET_START_DATE':
      return {
        ...state,
        startDate: action.startDate
       };
     case 'SET_END_DATE':
      return {
        ...state,
        endDate: action.endDate
       };
    default:
      return state;
  }
};
157
Q

How would you set up the getVisibleExpenses() function to (temporarily) return all the expenses (neither filtering or sorting)?

A
const getVisibleExpenses = (expenses, filters) => {
  return expenses;
};
158
Q

What arguments does the getVisibleExpenses() function need?

A

expenses (the complete array that’s going to be filtering and sorting) and filters.

159
Q

What does passing in expenses and filters to the getVisibleExpenses() function allow us to do?

A

Calculate what the visible expenses should look like.

160
Q

How would you add the getVisibleExpenses() call to store.subscribe()

A

NOTE: visibleExpenses gets set to the return value of getVisibleExpenses()??

store.subscribe(() => {
  const state = store.getState();
  const visibleExpenses = getVisibleExpenses(state.expenses, state.filters);
  console.log(visibleExpenses);
});
161
Q

What is the result of this code?

store.subscribe(() => {
  const state = store.getState();
  const visibleExpenses = getVisibleExpenses(state.expenses, state.filters);
  console.log(visibleExpenses);
});
A

The arrays printing to the screen.

162
Q

How would you destructure the filters argument to create variable for the individual ones with this code?

const getVisibleExpenses = (expenses, filters) => {
  return expenses;
};
A
const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses;
};
163
Q

How would you filter the data in this code without filtering it at all?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses;
};
A

NOTE: .filter allows us to return a subset of all of the expenses.
NOTE: When we have access to the individual expense, this allows us to determine whether or not it should be included in the visible expenses.
NOTE: .filter will only worry about text, startDate and endDate.

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch;
    const endDateMatch;
    const textMatch;
return startDateMatch && endDateMatch && textMatch   }); };
164
Q

What is happening in the return portion of this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch;
    const endDateMatch;
    const textMatch;
return startDateMatch && endDateMatch && textMatch   }); };
A

If startDateMatch, endDateMatch and textMatch are true the filter function will return true and the item will be kept in the array. If any of them are false the whole thing will result in false because we’re using &&, resulting in the item being removed from the array.

165
Q

What is a timestamp?

A

Any positive or negative integer value.

166
Q

What do timestamps count in?

A

Milliseconds.

167
Q

What does the timestamp 0 represent?

A

January 1st at midnight in 1970.

168
Q

What is the January 1st, 1970 timestamp know by?

A

The unix epoch.

169
Q

What does the timestamp 33400 represent?

A

33.4 seconds after midnight on January 1st 1970.

170
Q

How would you add some filtering to this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch;
    const endDateMatch;
    const textMatch;
return startDateMatch && endDateMatch && textMatch   }); };
A
const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch;
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
171
Q

What does

const startDateMatch = typeof startDate != ‘number’;

do in this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number';
    const endDateMatch;
    const textMatch;
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
A

If the typeof startDate is not equal to a number it will always result in true. So, if startDate is undefined we’re not going to take it into account when it comes to filtering. Therefore, it will always be true for non numbers which means we’re not going to get into a situation where the startDate is going to have an affect on whether or not an expense is visible.

172
Q

What is something to note about this line of code?

const startDateMatch = typeof startDate !== ‘number’ || expense.createdAt >= startDate;

A

If the startDate is indefined typeof startDate !== ‘number’ will result in true so startDateMatch will result in true (and in other part of the code) and the item won’t be filtered.
If startDate is 2 and createdAt is 1, typeof startDate !== ‘number’ isn’t going to be true so expense.createdAt >= startDate; will run. expense.createdAt is 1 and startDate is 2 expense.createdAt isn’t greater than the start date so this one is going to get filtered out.
If startDate was 0 and created at was 1, created at would be greater than startDate and it would once again be included.

173
Q

How would you test this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = true;
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
A

Set up some expenses and filters.

174
Q

How would you set up some test expenses and filters?

A
const expenseOne = store.dispatch(addExpense({
  description: 'Rent',
  amount: 54500,
  createdAt: 1000
}));
const expenseTwo = store.dispatch(addExpense({
  description: 'Coffee',
  amount: 500,
createdAt: -1000
}));
175
Q

How would you set up the startDate and endDate filters?

A

store.dispatch(setStartDate(125));

176
Q

What is the expected result of this code?

const expenseOne = store.dispatch(addExpense({
  description: 'Rent',
  amount: 54500,
  createdAt: 1000
}));
const expenseTwo = store.dispatch(addExpense({
  description: 'Coffee',
  amount: 500,
createdAt: -1000
}));

store.dispatch(setStartDate(125));

A

Only expenseOne should show up.

177
Q

How would you complete textMatch so if you enter some search text, only expenses that use that text value show up?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = true;
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
A
const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = expense.description.toLowerCase().includes(text.toLowerCase());
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
178
Q

What does the includes method allow you to do?

A

See if one string includes another.

179
Q

How would you set up some text filters?

A

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

180
Q

How would you use includes?

A

You call includes on a string, put the search string as the first argument and it returns true if the string is inside of your string, or false otherwise.

str.includes(searchString[, position])

181
Q

How would you add the sortBy functionality to this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = expense.description.toLowerCase().includes(text.toLowerCase());
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }); };
A

NOTE: The ternary operator is used on return.

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = expense.description.toLowerCase().includes(text.toLowerCase());
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }).sort((a, b) => {
if (sortBy === 'date') {
  return a.createdAt < b.createdAt ? 1 : -1;
}   }); };
182
Q

What is a compare function?

A

It allows us to write some code to determine which items should come first when looking at two distinct items.

183
Q

How would you create a compare function?

A
function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}
184
Q

How would you create a compare function?

A
function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}
185
Q

How would you add How would you add the sortByAmount functionality to this code?

const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = expense.description.toLowerCase().includes(text.toLowerCase());
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }).sort((a, b) => {
if (sortBy === 'date') {
  return a.createdAt < b.createdAt ? 1 : -1;
}   }); };
A
const getVisibleExpenses = (expenses, { text, sortBy, startDate, endDate }) => {
  return expenses.filter((expense) => {
    const startDateMatch = typeof startDate !== 'number' || expense.createdAt >= startDate;
    const endDateMatch = typeof endDate !== 'number' || expense.createdAt <= endDate;
    const textMatch = expense.description.toLowerCase().includes(text.toLowerCase());
return startDateMatch &amp;&amp; endDateMatch &amp;&amp; textMatch   }).sort((a, b) => {
if (sortBy === 'date') {
  return a.createdAt < b.createdAt ? 1 : -1;
} else if (sortBy === 'amount') {
  return a.amount < b.amount ? 1 : -1;
}    }); };
186
Q

test

A
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 {
      ..
    }
  };
  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 >
    )
  }
}
187
Q

test

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>
        Add Expense

  </div>
)   } }