Keys to getting a job:
- Brand passion
- research
- Internal ally
- best use of time
- network hard, coffee
- not job postings
- can give a clue
- placement agency
- can be black listed if double submitted at agency
- sometimes they may have keys to the job door with a client
Resume:
- 1 page
- where have I added value
- success metric
- carbon copy to job you are applying to, same language
- partner with a writer
Networking:
- design week
- go to open houses with the goal of making a coffee date
- sign up for events as they fill up
- Go to networking events
- Add speakers, hosts, and send note on linkedin
- "hey I see you are hosting / speaking at .... I look forward to seeing you there / meeting you"
- write down / keep track of their information
- go to the event and try to meet them in person
- tell them your wants and needs
- I am a front-end javascript dev looking for work in ....
- grab business card and go home and add them on linkedin
- add them to tracking information
- Add speakers, hosts, and send note on linkedin
- connect by finding them on twitter / social media and a physical letter / note
- "hello ... I am excited to talk to you about your experience in... and would love to take you to coffee on these dates at these places?"
- informational interview
- don't come off as "I don't want this job, I need a job"
- look at their linkedin
- look at company website
- look at news tab in google
- have them talk about themselves
- send meeting request for calendar invite
- say "psyched to see you tomorrow" (check in)
- company culture, turn over, projects they are working on
- how can you contribute?
- ask for feedback on github, what would make me a stronger candidate for this job?
- ask "Hey is it okay if I reach out to HR and mention we had this meeting?" for name drop
- end with an offer
- Can I volunteer at your next event?
- ask "what is the compensation range I should be asking for in interviews"
- "I have a strict non-disclosure agreement with prior employer. I'd like to ask if there is a range"
- "right now I'm having conversations about opportunities in the 68k range"
- nurture network
- send out cards, checking in, care!
- even if full time employment, keep it up as it is false safety
- "hey I'm heading to the ... event, want to meet there?"
- "I would love to contribute to your team"
When in job:
- track success metrics while in job! Push for compensation increase and title change. Ask for your worth.
- be candid about opportunities "I appreciate the offer but I am also negotiating with my company"
- "I really want to be here, but I have an offer of $x, can you match or beat it?"
Speaker: Richard Stanley
- Director of applications / dev advocate
- rstanley@apexsystems.org
- can help look for jobs elsewhere in country
Networking directly and showing code to those who have jobs in industry
- referrals are important and lead to jobs
Personal projects
- ask yourself about something that you need or want and build it (search that looks for open source projects that need help on github)
- search by expertise in projects
Social media
- follow on slack, twitter, and stack overflow
- Portland devs prefer twitter?
- offering help on Stack overflow?
- slack
- frontend developer
- look for software to contribute to and ask to join slack
Meetups
- calagator
- PDX women in tech
- PASS (SQL)
- Javascript
- PDXNG
- NodeJS
- DoughnutJS
- Project Management Institute (PMI)
- curate network
- only add people you know
- don't add recruiters unless you've talked to them at least on the phone
Resume
- keep it at one page
- give a longer one if they ask for one
- "things i've done in my spare time"
- by project, say what YOU did, not what is in the project
- volunteer work, internships, github projects, freelance work, education, personal website, hackathons, certs / bootcamps, linkedin profile, skills (for ATS)
- order skills at top if they are all stuff you can talk to, place at bottom if it's just for ATS
Job sites
- indeed
- monster (bad, but get calls)
- dice
- apex Systems (will not call you unless you are a good fit)
- careerbuilder (bad, but get calls)
- stackoverflow
Applicant Tracking Systems
- keyword matching
- filters out resumes
- jobscan.co/promo/apex
How to work with recruiters
- staffing firms
- work for clients to find employees for client
- corporate
- work for the company to find talent
- consulting firms
- often contracting positions
- bring in talent for a particular project
- leave when project is done
Recruiters
- resume reviews, mock interviews, market trends, keep in touch
- get a phone call once every 3-6 months
- proactive submissions
- send resume to places that aren't even hiring, but positions will sometimes be made for you if you are good enough
- pipelines
- work closely with one or two recruiters and build a relationship
- if they don't spend time on these things, move on
Pleuralsite
- subscription website for continued education
- download on phone listen to like podcast
After first job
- stay in job for at least a year and move on, especially for wage increase
- find some niche new technology and learn it, make $$
- inflation is 6%, usually only get raises that are 5% at best. Leave!
- 5 years is average time to be at a job
Negotiation
- with recruiters: can negotiate more cash
- ask for 10% above what they say they can give, if no budge wait until next day and go a little lower
- small locale firms give you bigger push
- pitch recruiters against one another
- recruiters only get paid during length of contract
- with company directly: can negotiate more benefits
- costs them less than actually pay more
- more PTO, continued learning, parking, transit, flexible hours
- weaker negotiation space
- "what is this position looking to pay?"
Interviews
- closely typed vs loosely typed
- polymorphism
- book: Design patterns: Elements of reusable object-oriented software
- talking shop with patterns
- talking in terms of concepts
Creative Staffing Agencies: 52LTD: 52ltd.com Aquent/VitaminT: https://vitamintalent.com/ Mathys Potestio: http://mathys-potestio.com/ 24|Seven: https://www.24seventalent.com/en-us/home
Tech Staffing Agencies: Apex: https://www.apexsystems.com/Pages/default.aspx CorSource: http://www.corsource.com/ KForce: https://www.kforce.com/ Vanderhouwen: http://www.vanderhouwen.com/
Testing actions with Firebase
-
Create firebase
.on('value')
event listener that will dispatch an action for every value change for the listener -
have the
.on('value')
anddata.val()
separate from the action for the listener so it is easier to mock. These can live inside the firebase api in a function that becomes a service call -
you can try to mock
.on('value')
but it is less fun -
ongoing action creators need to be kept from being recalled
- keep in app so it is only loaded once
- not the best since app owns stuff that should belong to other components
- keep track of listening
true / false
in action creator
let listening = false; export function action() { if(listening) return; listening = true; // changes it after the first call }
- keep in app so it is only loaded once
-
firebase gives back an object but we will usually want an array to iterate over in creation of VDOM elements. This also allows us to add a key property that is the firebase key for that item.
-
utilize firebase verbage in actions
setNoun
,getNoun
User Auth
auth.onAuthStateChanged
will fire when there is a user state change.- create an action that listens for a user in high level component (App)
- must be a thunk
- have a reducer that sets the new user
actions:
export function listenForUser() {
return dispatch => {
auth.onAuthStateChanged(user => {
dispatch({
type: USER,
payload: user
})
}
}
}
- firebase Auth does come with a pre-rolled auth UI
npm i firebase UI
- add style-sheets in index.html that come with the UI
- comes with success callbacks
- go into firebase console Auth and turn on sign in methods desired
- place into component
const ui = firebaseui.auth.authUI(firebase.auth())
- turn off credential helper as it is annoying
- create components for sign up / sign in / sign out
- the way that firebase works, some actions will be listeners on changes in firebase, so actions for making changes in the app that affect firebase may not always be needed as long as a listener already exists
- listenForUser
- after a user is successful in creating an account, redirect them back to where they came from
Private Routes
- will handle if there no user, send them to the login page
- include a state.from property to go back to wherever the user was
- can be found in
this.props.location.state.from
- use in-leu of the
<Route>
tag from Router use<PriaveRoute>
random notes
- in a switch statement, if cases do the same thing, you can stack them:
switch(type) {
case END_GAME: //will flow to the next case
case NEW_GAME:
return null;
}
firebase REST API
- when fetching to a RESTFUL API with firebase, you can use
URL/${something}.json
to obtain a JSON object of the data - if you store data with a number in firebase, it infers you are organizing an array and will return
null
for the 0 position npm i firebase
to link the dependency- get and post will work with the app
- firebase will return an object from a requested node. Do
Object.keys
to turn it into an array to iterate over - will not be able to sort results returned, will have to do on the front end
React Checklist
store.js
- import
createStore, combineReducers, composeEnhancers, applyMiddleware
- import reducers
- combine those reducers
- call createStore
- pass in "combined" root reducer
- use composeEnhancers and applyMiddleware to include all needed middleware plus make REDUX_DEV_TOOLS word
thunk
- you need access to
getStore
- you need to make multiple calls to dispatch
- async, if not fitting into promiseMiddleware
- you need access to
promiseMiddleware
- want action creators to be simple and pass a promise as the payload
- can give preset data so presentation components have some data to work with
- export store
index.js
- import
Provider
fromreact-redux
- import
store
- wrap app component in
<Provider store={store}></Provider>
- Create reducers by features in various component folders
- export named function per data that needs to be in the store
- Create action creators by feature
- use
connect
to:
- inject parts of the store state as props into component
mapStateToProps
- there is a second parameter in mapStateToProps that allows parent props to be passed in
mapDispatchToProps
- ``(dispatch) => { //return object of props (which are functions) to inject}
- can leverage bindActionCreators built in by passing an object ``{ actionCreator1, actionCreator2 }
- sometimes can use
mergeProps
third parameter to do more - pass
null
to a parameter if don't need a piece of connect
export default connect(
({ commentsByNote}, {id}) => {
comments = commentsByNote(id)
}),
({ actions }),
({ nameSomeProps}) => { merge them })
thunk testing
it('resolves a thunk', () => {
const index = 0;
const selection = 'rock';
const result = makeChoice(0, 'rock');
const dispatch = jest.fn();
const getState = jest.fn(() => ({selections:[]}));
result(dispatch, getState);
expect(dispatch).toBeCalledWith({
type: SELECT,
payload: { index, selection}
})
expect(dispatch.mock.calls.length).toBe(1);
expect(getState).toBeCalled();
});
children components
- when components are passed as children inside of other components, a property called
this.children
is accessible within the parent component - you can also pass in a function this way, though it is preferred to pass it as a prop with
render
prop for consistency
<Parent stuff={stuff}>
<div>{child}</div>
</Parent>
- sometimes you will need to access the DOM node itself
- Ex: have an input box auto-focused on load
- use can do the same with a component, though less common
componentDidMount() {
this.nameInput.focus();
}
<input ref={node => this.nameInput} = node/>
ReactCSSTransitionGroup
- injects as a span
- children of the transition group must have a key to differentiate itself
- utilize class names
enter
andleave
, but you can declare your own if you want - timeouts must have same value as transitions in CSS
- opacity and transform are best preforming properties in transitions
in jsx:
<ReactCssTransitionGroup
transitionName="fade"
transitionEnterTimeout={500} //milliseconds
transitionLeaveTimeout={300}>
{thingsToTransition}
</ReactCSSTransitionGroup>
in CSS:
.example-enter {
opacity: 0.01;
}
.example-enter.example-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.example-leave {
opacity: 1;
}
.example-leave.example-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
Closures
function makeSayIt(total) {
return function more(str) {
if(!str) return total;
total += str;
return more;
}
}
const sayIt = makeSayIt('');
//then call sayIt with whatever
random notes
React Router
- can use
render={() => }
method on props for aRoute
to give specific props likematch, location, history
- can use render to pass specific functions from parent if need be
- when using component syntax
component={ComponentName}
- match is an object with information on how a link was matched with a route
match.params
will extract the /:param part of the url (sub-routes)- EX: https://localhost:8080/users/:id/:name -> https://localhost:8080/users/123/grace -> match.params: { id: 123, name: grace }
- can bring these properties in through the connect() statement with redux, or directly into the component through
this.props.match.id
with connect:
export default connect(
(state, props) => ({
users: state.users,
albumId: props.match.params.id //brings in the album id from url
}),
{ loadAlbum }
)(AlbumDetail);
- cannot use unknown parameters in
<Link>
.- Ex:
<Link to="/albums/${match.params.id}/books></Link>
- Ex:
withRouter
wraps component to give it history context when it is not a direct descendant of the<Router></Router>
- use
history.push('new/location')
to programmatically change a location, such as within a function
Jest mock
- import the api into the test, then check to see if it was called with was you expected it to be called with. Will check if it was forgotten / missed.
import galleryApi from '../../services/galleryApi';
expect(galleryApi.add).toBeCalledWith(image);
Promises
- always asynchronous
- a callback
- only happen once
- rarely use
new Promise()
- most apis will create a Promise itself
.then( () => function stuff )
- will take what is returned from a promise and allow you to do something with it.
- can chain as long as each one returns something
- smart enough to know when it is handed a promise and wait to return the value given by that promise!
- can be chained inside of a function and still be used within another promise chain!
.catch( err => do something with err )
- only needed once at the end of a promise chain
- will catch any error along the way, stops in chain where error happened
- place it on the level of the originator, not nested within others
- can place a
.then()
after and it will always happen
throw
- creates a failure within a
.then()
,.catch()
will catch
Promise.all()
- allows you to wait for all promises to do their thing and return, then you can call
.then()
for all of them
Promise.resolve() / .reject()
- create a promise that will succeed or fail.
- Async / await *
- function that returns a promise, use
async
to denote the async function, thenawait
after that function to mimic.then()
async function Something(this) {
const files = await asyncThing(this);
const somethingElse = sync(that);
const anotherThing = await asyncStuff(hmm);
return anotherThing;
}
Something(this)
.catch(err => err stuff);
state game v2 demo
- to listen on a keypress, must have the listener on the entire document
- have a guard clause to protect against all other keys in listener
random notes
building a react app
- presentation components
- receive props to create VDOM
- can callback functions from parents on events
- container component
- connect() in redux
- figures out what state from the store is needed, what functions from action creators
- parent component
- organizes placement of children
- passes data to children
- action creators
- functions that create actions from the store
- handle side effects (impure)
- selectors
- can be impure with caching (reselect)
- typically used in mapStateToProps in connect()
- are given state and do things to it
- redux middleware
- do special things on certain actions
- not always necessary
- reducers
- pure functions that return a new state
- live in store
- store
- where the state and reducers live
- services
- expose functions for communicating with external resources
- advised to start with presentation components. Then create reducers (first) and actions. Then create the store and container component, etc.
- draw the wireframe with components outline and named
- create tree of components with data flow of parents to children
- create routes with mini wireframes
:local(.className)
creates a dictionary where the key is the class
import styles from './cssFile.css';
- comes from webpack css-loader
Import hash-router as Router to help with refresh data save.
mock tests (actions with side effects)
- want to be able to isolate action and test it without worrying about API failures
- inject api method is tedious and would need a new injection for each test of the action
- do mocking instead on jest
- pace mocks before imports, though is not necessary
jest.mock('../../services/api, () => ({
getAlbums: jest.fn(() => Promise.resolve('PAYLOAD'))
}));
Promise.resolve()
will succeed with whatever it is given- did the result of calling getAlbums assign to payload on the action creator?
- you can pass in
done
to jest's it() tests, and calldone()
when you are done after an async test - jest mocks are hoisted to the top of the document
Types of react components
- 3rd party components, look for stars, when completed, last commit
Pure Components
class ThisClass extends PureComponent
- use with redux / immutable data styles
- will follow immutable data rules and will not re-render if inputted data is the same as previous data
- pure function components do not have the lifecycle method shouldUpdate()
- use destructuring with spread operator when passing into a function to allow for variable props
const TextControl = ({ lable, ...rest }) => {
<label> {label}:
<input {...rest}/>
</label>
}
Styled Components
- 3rd party component
npm i styled-components
- uses a tagged template literal as a function call
import styled from 'styled-components'
const Button = styled.button`
color: steelblue;
background: white;
${props => props.primary && css`
background: palevioletred;
color: white;
`}
`;
//can be used as
<Button/>
//can add props in (like a class name!)
<Button primary/>
- can utilize conditionals / javascript!
- if you want to switch back to css inside the javascript, use
css
with backticks
const fancyListItem = styled.li`
color: ${{ name } => name[0].toLowerCase() === 'j' ? 'blue' : 'green'};
`;
- allows to drive styling off of data
- don't mix component styling with styled sheets!
- can style any component by passing in the
className
prop
ReactModal
- component for popup modal
- tell it whether it is open or not
random
- you can use connect to grab props of the parent component. This comes from react-router
(state, props) => ({
notes: state.notes,
user: props.match.params.user
})
selectors
- have their own reducers
- when creating a filter, have it must be a controlled component
- create a function (the selector) that converts state data into what you want
- export the function within the reducers file
- apply it within the connect statement
- there is a movement to place selectors for everything within reducers, so that the connect statement is pure and does not modify data itself
reselect
- memoization of data (re-uses cached values when possible)
- pass in state to the selector, it is intelligent about what to pull off
npm i reselect
createSelector([array of states], (states) => {
//do something
});
random notes
- Connect
- takes a component, then returns that component with relevant pieces of state and dispatchers mapped to props wrapped within another component.
- the dispatch part of the connect function has some shorthand as the boilerplate was repetitive.
export default connect (
state => ({ notes: state.notes }),
{ makeNote: addNote, fetchNote: loadNotes }
)(connectedComponent);
Error handling
- app wide vs per feature?
- do both! specialize when needed.
- app wide dealing with a loading spinner
- stays with the header / footer since they are displayed on every page
- re-type error messages within the async action to be more user-friendly
- when using fetch
- there are often responses even if the response was not 'ok'
- must check with the response is ok to return
response.json()
if there is a response without an ok response:
.then(response => {
response.json().then(body=>{ //smart about where the error resides
if(body.message) throw body.message;
if(body.error) throw body.error;
throw body;
})
})
- combine fetching and error handling into own wrapper function in api calls
- if you find yourself dispatching the same two actions together, combine them
- such as error clearing with loading of the page
- better UI to not clear user input on failed form submission!
- place clearing of the form inside of a promise that only fires if successful
- throw the error in the action so that it can be picked up elsewhere if needed
- can get pretty redundant, utilize middleware to wrap a promise in error handling stuff!
const promiseMiddleware = store => next => action => {
const { type, payload } = action;
if (!isPromise(payload)) return next(action);
//handle action here
}
- if a reducer is expecting a certain format of payload from an action with async, but that action is presenting the payload in a different format for API calls, you can always chain a .then() and present the payload in the desired format
- useful when the server is returning something that we don't need but we want to change it into something more useful after the promise is fulfilled
export function removeNote(id) {
return {
type: NOTE_REMOVE,
payload: notesApi.remove(id).then(() => id); //implicit return of id for reducer that expects an id instead of what the .remove() is returning
}
}
Loading
- sometimes easier create the reducer inside of the test file when starting.
- initial state of loading should be false, no need for a payload
- specific actions are not needed since loading is always triggered by async actions
- will dispatch loading action from fetch action
- Promises
- the second parameter of .then() allows for an error handling function, which can catch errors that happen within the .then() promise.
console.dir
will be more intelligent at displaying what it is attempting to display- create a reducer within the loader if there is an error
- set the loader to false if there is an error
describe('initial state', () => {
it('initial state', () => {
const state = error(undefined, {})
expect(state).toBeNull();
})
it('sets an error', () => {
const state = error(null, {type: ERORR, payload: { message: 'error' } });
expect(state).toEqual({ message: 'error' });
});
it('clears an error', () => {
const state = error({}, { type: ERROR_CLEAR });
expect(state).toEqualNull();
});
})
Testing async actions
- use dependency injection
- 3 choices
- mock the dependency (api)
- change actions so that they accept an api argument that will allow injection of any api, confusing
- create extra argument in promise middleware (learn tomorrow)
- iterating through every element in a tree
- go to the left (not access, go there and make next decision)
- go to the right (not access, go there and make next decision)
- visit current element (access value)
- visit left before right on child nodes
Depth first
- pre-order
- as soon as a node is reached, read its value
- in-order
- left children, then parent, then right children
- post-order
- parent after children
Breadth first
- visit nodes siblings prior to children
- Use case: mathematics
- reverse polish notation (parent is after children)
- 3 12 7 - *
- no need to parenthesis
- reverse polish notation (parent is after children)
infix operator
function infix(node) {
let string;
if(node.left) string+= infix(node.left);
string+= node.value;
if(node.right) string+= infix(node.right);
return string;
}
Tree rotation
- to help with tree balance when adding and removing nodes.
function pivot(str, node) {
let direction1, direction2;
if(str == "left") {
direction1 = "left";
direction2 = "right";
} else {
direction1 = "right";
direction2 = "left";
}
const newParent = node[direction1];
node[direction1] = newParent[direction2];
newParent[direction2] = node;
return newParent;
}
Connect
map dispatch to props in long form:
dispatch => {
return {
addNote: function(note) {
const action = addNote(note); //action creator called addNote in actions.js
dispatch(actionGoesHere); //dispatch the action
}
}
}
- there is the store
- actions are injected into the store by calling dispatch with the action creators (we call actions by shorthand)
- store is holding the reducers. Takes the action and updates the state.
- store sends out a new state, which will trigger re-rending of relevant components
middleware
- an action is created
- prior to that action heading off to dispatch, that action can pass through functions (middleware).
- intercepts dispatch call and modifies data
const logger = function(store) { //longhand
return function(next) {
return function(action) {
if(action.type === 'COMMENT_ADD') {
action.payload.text += ' haha!';
}
}
}
}
//shorthand
const logger = store => next => action => {
if(action.type === 'COMMENT_ADD') {
return action.payload.text += ' haha!';
}
return next(action);
}
const store = creteStore(
reducer,
composedEnhancers( //for redux dev tools
applyMiddleware(
logger
)
)
);
- when dealing with asynch, must only send data to dispatch if the data response was successful
- cannot create with synchronous actions
- use thunks!
- return a function that will call dispatch when they are done with their business
const asyncanator = store => next => action => {
if(typeOf action === 'function') {
action(store.dispatch); //inject dispatch back if the given action is a function
}
else {
return next(action);
}
}
const store = creteStore(
reducer,
composedEnhancers( //for redux dev tools
applyMiddleware(
thunk
)
)
);
Redux Thunk
- can be used to further simplify actions
- direction presses reduced into coordinates for a single move instead of reducers for each direction press
- use with fetch()
response.json()
will turn the response into a json parsed
Store
- combination of state and reducers
- store has three methods:
- dispatch: send an action to the store reducer
- subscribe(listener): be notified when store state "changes"
- getState(): get the current store state
- when a store is not yet created, will send
{ type: '@@redux/INIT }
as first action - all actions will flow through all reducers with
store.dispatch
as there may be multiple reducers for the same action type. - createStore(reducers, [initialData], [enhancer]) has an option to see initial data
- good for development environment
- make sure to add reducers into
store.js
!
Connect
- writes a component that will talk to store
- will connect a component to the reducers, actions, and data store
- mergeProps
- ownProps are passed from a parent to a child
(stateProps, dispatchProps, ownProps) => {
return { // desired props
alias: stateProps[specificKey].
alias: dispatchProps,
ownProps: ownProps
}
}
Combine reducer
- will take in actions and send them to reducers
- checks if reducers produce a new state
- if new state is produced, return it, if not, return current state
- pass in a map of child reducers to combine to pass to the store
- can bring reducers with aliases
CommentsBy: CommentsNotation
- reducers are always synchronous
const reducer = combineReducers({
pets,
people: combineReducers({ //can combine in multiple nestings
good: goodPeople,
bad: badPeople
})
});
Demo
- create a reducer that will support expensesByCategory
- create a map that will have a key that is the key of the category
- an array of the expenses is beneath this key
//start
expensesByCategory = {};
//end
expensesByCategory = {
categoryId: [
{
name: 'expense name',
amount: 'expense amount',
id: 'expense id',
timestamp: 'expense date'
}
]
}
Random Notes
- npm i shortid to generate random short ids
- command + shift + k deletes an entire line in VS code
State
presentation
- dumb, take props, generally do not have state
- action creators
actions
- obtain the events that happen in an app
- will dispatch state changes
- call these from component to dispatch desired reducer
- app logic happens here to change the given object
in actions:
import shortid from 'shortid';
import { NOTE_ADD } from './reducers';
export function addNote(text) {
node.id = shortid();
note.timestamp = new Date();
return { //returns the action
type: NOTE_ADD,
payload: note
}
}
state management
- lifted away from components
- more easily accessible my components
- state will flow back down to re-render a component with updated props
- in redux, there is one store where all the data lives (single source of truth)
- except local component state
- akin to the url being the single source of truth for react router
reducers
- changes a state based off action
- typically at least one reducer file per component
- app logic DOES NOT HAPPEN HERE
- components should NEVER directly talk to reducers, only actions do that
jest unit reducer test:
import { notes } from './reducers';
it('has a default', () => {
const state = notes(undefined, {});
expect(state).toEqual([]);
});
it('NOTE_ADD', () => {
const noteToAdd = {
id: 123,
timestamp: new Date(),
text: 'New note'
}
reducer(notes([], { type: 'NOTE_ADD'. payload: noteToAdd}));
expect(state).toEqual([noteToAdd]);
it('removes a note', () => {
const state = notes([noteToAdd], { type: NOTE_REMOVE, payload: 123})
expect(state).toEqual([]);
});
it('updates a note', () => {
const updated = {
id: 123,
text: 'updated note'
}
const state = notes([noteToAdd], { type: NOTE_UPDATE, payload: updated});
expect(state).toEqual([{ ...noteToAdd, ...updated }]);
})
}
reducer:
export const NOTE_ADD = 'NOTE_ADD';
export const NOTE_REMOVE = 'NOTE_REMOVE';
export const NOTE_UPDATE = 'NOTE_UPDATE';
export function notes(state, action) {
switch(action.type) {
case 'NOTE_ADD':
return [
...state,
action.payload
]
case 'NOTE_REMOVE':
return state.filter(n => n.id !== action.payload);
case 'NOTE_UPDATE':
const index = state.findIndex(n => n.id === payload.id);
return [
...state.slice(0, index),
{ ...state[index], ...payload },
...state.slice(index + 1);
];
default:
return state;
}
}
immutable data
- Component Life-cycle Methods
- constructor
- componentWillMount
- Nobody uses this ¯_(ツ)_/¯
- componentDidMount
- Fetching Data
- componentWillReceiveProps
- Need to use when updating component that does not re-render
- shouldComponentUpdate
- Prevents unnecessary updates
- skips rendering when no change in data
- componentWillUpdate* and componentDidUpdate*
- Nobody really uses these ¯_(ツ)_/¯
- render +1
- create a new version of an object with changes instead of mutating
- makes comparison of previous state and new state much easier (direct comparison)
- no need to loop through nested items / check every little thing
Working with immutable data:
const person1 = {
name: 'lady'
}
//add
const person2 = {
...person1,
name: 'good sir' //overwrites any previous stated properties
}
const toys1 = ['cat', 'bat', 'kids'];
//add to array
const toys2 = [
...toys1,
'banana'
];
//delete (usually has id)
const toys3 = toys2.filter(t => t !== 'cat');
//insert
const index = toys3.indexOf('bat');
const toys4 = [
...toys3.slice(0,index), //copy up to item of interest
'mouse', //insert desired item
...toys3.slice(index+1) //add everything past item of interest
];
//adding to array of object
const complex1 = {
name: 'katy',
toys: ['cat', 'mouse']
}
const complex2 = {
...complex1,
toys: [
...complex1.toys,
'sand'
]
};
const complex4 = {
{ name: 'jazz', color: 'red'},
{ name: 'greg', color: 'orange'},
{ name: 'sam', color: 'cans'},
}
const indexOfJazz = complex4.findIndex(p = p.name === 'jazz');
const jazz = complex4[indexOfJazz];
complex5 = {
...complex4.slice(0,indexOfJazz),
{
...jazz,
color: 'grey'
},
...complex4.slice(indexOfJazz + 1);
}
store
- where the app data exists
- app is wrapped by a
Provider
class where thestore
sits
connect
- creates the container component for the presentational component
- links state and actions to the component
- not necessary to add state if not needed
Design
- use
htmlFor
instead offor
in inputs and labels - have an input field inside of a label and use the
htmlFor
attribute - use
<></>
to wrap text so as not to create too many divs - when mapping and a key is required, use
<fragment></fragment>
random notes
- webpack 4 was released. When creating a new project, specifically install webpack 3.11.0
- scrum is a particular subdivision of agile development method.
- utilize user stories.
- estimation would assign a value metric to user stories to gauge the effort needed to accomplish that story.
- add up points from estimation from previous projects to help estimate what can get done in the future
State
- will mostly be removed from components with redux in a center that controls state
State game
- rooms:
- treasure room
- great hall room
- starting room
- bird cage room
- what does a room have:
- description
- doors
- directional: E, S, W, N
- items
- key
- 'start'
- 'treasure'
- use method
- when an item is used in the room
- create a room component that works with the room object
- player:
- inventory
- items leave the room and enter inventory
- inventory
Demo
- when state is rich with information, create a separate file to store it
- start with
- can turn prop-types off in eslintrc.
Object.keys
will take the key names from an object and push them into an array.- when setting state on the content of state, should always use a function as it is handled asynchronously
- if you want the room to automatically update, you must give it a key so react knows you aren't just changing props
layers deep in a tree
- max tree:
n-1
- min tree:
(log2(n+1))-1
factorial
- recursive
function factorial(n) {
if(n>1) return n*factorial(n-1);
else return 1;
}
happyNumbers
function happyNumbers(n, prev={}) {
let digits = n.toString().split('');
let squares = digits.reduce((total, digit) => total + (digit*digit), 0);
if(squares === 1) return true;
if(prev[n]) return false;
prev[n] = true;
happyNumbers(squares, prev);
}
Letter permutations
function perm (letters, parent='') {
if (letters.length === 1) return console.log(parent+letters[0]);
for(let i=0; i<letters.length; i++) {
const copy = letters.slice();
const [letter] = copy.splice(i,1);
const stem = parent + letter;
perm(copy, stem);
}
}
random notes
- VSCode when cmd + d, can change casing sensitivity by opening up cmd + f
find
and change with the casing button. - object spread
const person = {name: 'Tammy'}
const obj = {
color: 'Blue',
...person
} // adds person to obj. Will take the right-most and overwrite if properties are the same
- for omdb reference:
.then(json => json.Response === 'True' ? json : { error: json.Error })
- in general, create a check notification function
Testing
- will use
jest
andenzyme
Jest:
it('passing test', () => {
const foo = true;
expect(foo).toBe(true);
});
it('failing test', () => {
const foo = true;
expect(foo).toBe(false);
});
test
orit
will do the same thing- Test runner will allow code to be written and test it. The prior passed code will be saved as a snapshot in
*.test.js
. - Will throw an error with nice messages, specific to what changed.
- Double flag (--) in scripts of
package.json
tells npm to add jests watch
"scripts": {
"test": "jest",
"test:watch": "npm run test -- --watch",
},
- jest will behave differently. Will clear out the consol and add more options
- update a snapshot
npm test -- -u
- have multiple tests based on if a component exists or not
- Enzyme will help with testing components (click something, expand something, toJSON)
{shallow}
rendering from enzyme stops at children (components)
Steps to Creating a snapshot
- create a static component to render
- apply styling if need be
- add functionality to elements (onSubmit, onClick, etc.)
- add
*.test.js
of the component - add tests for different forms of component
- simulating functionality
- run jest to create snapshot
describe('Component' () => {
it('Renders design', () => {
const wrapper = shallow(<Component/>);
expect(toJSON(wrapper)).toMatchSnapshot();
});
})
it('Calls onAction with criteria entered', () => {
let filter;
const handleAction = _filter => filter = _filter;
const wrapper = mount(<Component onAction={handleAction}/>); //mount has more actions than shallow
const action = 'action given';
// stuff to simulate action
expect(filter).toBe(action);
})
- build propTypes based on props
- add in props that will be passed into component
- requires us to think through how a component should be built
Router
- High level routing usually lives on App.js
historyApiFallback: true
will serve index.html page if no router matchLink
tag similar to<a>
tag. Will render as tags. Do not place empty tag in react. Will only change what is in the url bar.Router
wraps all elements where routes will be servedRoute
wraps components that will be at a particular route. Will only change by what is displayed in url bar.- if you place content inside of these tags, they will render if the element is NOT matched
exact
attribute on route will match exact route onlySwitch
element is like a switch statement, will only match the first one and none of the others- Place routes in their own component for easier readability
Redirect
is a fallback if there are no route matches inSwitch
render
is an attribute on route that will take a function (usually involving match) and render the component with the result as the props
import {BrowserRouter as Router, Route, Link, Switch, Redirect} from 'react-router-dom';
- can use
Route
to create special stuff in the header based on the url path!
random notes
- Bulma for pagination in css
- :local(css-selector) will create a key to give to a react component for scoped CSS styles
Components
- Think of:
<MyComponent foo={foo} bar="BAR" onQux={this.handleQux}/>
- As:
const myComponent = new MyComponent({
foo: foo,
bar: 'BAR',
onQux: this.handleQux
});
- Components are brought in by:
render() {
<MyComponent/>
}
- props are brought in by:
render() {
<MyComponent name={12}/>
}
- and can be accessed by this.props automatically on the child component MyComponent. Sometimes you pass in props in a constructor in the child component, but only when state needs to be derived from the income props.
constructor(props) {
this.props = props // not always necessary
}
- now with class properties (dedicated syntax):
state = {
count: 1,
name: grace
};
- class properties with bound
this
:
handleUpload = () => {
this
}
this
rules:- unless explicity set by .call(), .bind(), .apply(), will be the thing to the left of the dot at the call site
- unless it is an arrow function, then
this
is wherever the arrow function was defined (lexical scope)
- .setState() is asynchronous.
- any time you want to setState() based on the previous state, use functional form of state
this.setState(prev => {
return { count: prev.count + 1 };
})
- when state changes, the component is not re-initialized, but is simply rerended based on state change.
- will re-initialize if you add a
key
to the component that is tied to state change - re-rendering does not always happen with state change
- will re-initialize if you add a
- conditionals can render in a hide / show manner
- .setState() accepts a callback to innact after it is done
<span onClick={() => this.setState(prev => ({ expanded: !prev.expanded })))}>{ expanded ? `close` : `open'}</span>
{ expanded ?
<B name={number}/> //opens the B component
: null //will show nothing
}
- alternatively:
{ expanded && <B/>} // if expanded is true, will show B!
{ expanded || <B/>} // if expanded is false, will show B!
State
- Rules of state
- Sibling components that share state? Must live in common ancestor
- Push state a far down as possible
- Props are state passed from a parent component
- Child components never modify props directly
- Never set state outside of constructor
- Never call setState during synchronous part of render()
- Use setState(fn) when using previous state
PropTypes
- dev time feature
import PropTypes from 'PropTypes';
static propTypes = {
number: PropTypes.number.isRequired
};
- helps with testing
Search & Pagination
- all state will exist on APP in this small case
- break up components
- search bar
- pagination
- results display
- number of results & search term
- state
- total results
- results per page
- current page
- query
- results
- page requested
- assign states to components
- results display
- results
- results per page
- search bar
- query
- pagination
- page requested
- number of results & search term
- query
- total results
- results display
- information to pass to API from APP
- query
- page requested
- per page
- information returned from API to APP
- results
- page
- component tree
- APP
- results -> list
- onsearch -> search
- total results, results per page, onPrev, onNext -> paging
- APP
demo
App.js:
state = {
results: null,
total: 0,
query: null,
page: 1,
loading: false
}
- pick between uncontrolled and controlled form types. controlled is linked with state.
- when you add a state link to a form component, anything you do to that state will render in the form element
- Ex: .toUppercase() on target in a form input, the input will render with uppercase letters.
- on submission, would probably want to submit the state then.
random notes
- frameworks / libraries often do the heavy lifting for you so you don't have to interact with the DOM any more.
- Babel will take ES6 code and transpile it into ES5. Allows use of newer features that browsers do not yet support.
Eslint
- install eslint-plugin-babel, eslint-plugin-react
Webpack
- Build step by step and check that it worked.
- webpack config files are build using node, thus uses older require() format instead of import/export
- any time config is changed, must restart dev server
- start and test do not need "run" prior to them in
npm start / test
- Loaders
- become involved with import/require
- Plugins
- do additional work on the resource tree
- Ex: clean-webpack-plugin, give it a string path of where to clean
- entry point
- where webpack will look to seek dependents
- output
- where wepack will place the build
- bundle.[hash].js
- hash is a cache buster, randomizes the bundle name with each build
- path must be hard coded in webpack
- ${__dirname}/build
- npm adds the direct path location of webpack when you do
npm run build
- webpack-dev-server
- auto refereshes changes
- npx will do some magic and find location of path for command given
- contentBase set to ./build.js
- html-webpack plugin adds javascript in script tags into html
- inline-source-map
- a map between the bundle and what you actually wrote. Makes debuggin in the browser bearable.
- command + p will bring up desired files
- need to add a .babelrc file:
{ "presets": [ [ "env", { "targets": { //will be smarter about transpiling "browsers": "Chrome 60" //can do 'last two versions' } } ] ] }
- babel-core, bable-loader, bable-preset-env
- placed as a loader in module rules
- post-css allows nesting
- css-loader allows css to even work
- auto-prefixer auto prefixes
React
- npm i react react-dom eslint-plugin-babel eslint-plugin-react
- must tell babel to change JSX into React.createElement() in .babelrc
import ReactDOM from 'react-dom';
import React from 'react';
ReactDOM.render(<div>Hello world</div>,
document.getElementById('root'))
- pretend components are an element
<App />
and react will call that component - even though the entire render() method is called during a setState(), only the changes are rendered in the DOM.
import React, { Component } from 'react';
export default class App extends Component {
constructor() {
super(); //do not forget to call!
this.state = {
name: 'Portland'
};
handleNameChange({target}) {
this.setState({
name: target.value
});
}
}
render() {
const { name } = this.state;
return ( //not necessary but to help for readability
<div>
<div><input value={name} onChange={ event => this.handleNameChange(event)}/></div> //eventListeners are camelCase
<div>
Hello {Name}! //interpolation via single curly braces. don't need extra white space like objects
</div>
</div>
);
}
}
- State -> render() -> virtual DOM -> compares to last virtual DOM -> DOM changes -> events -> actions -> changes to state -> back to State
- There are multiple ways to resolve the
this
problem within react.- when event listeners are created within the render method, it will be recreated each re-render, which isn't so bad but is annoying to the community
- binding
this
to each method on the class in the constructor
in JSX creates a non breaking whitespace- when styling inline in JSX:
<input style={{
backgroundImage: background ? `url(${background})` : null
ref={node => this.section = node} //to remember the node referred to
}}/>
<input type="file" onChange={handleUpload}/>
- base64 loading of file upload
handleUpload({target}) {
const reader = new FileReader();
reader.readAsDataURL(target.files[0]);
reader.onload = () => {
this.setState({ background: reader.result})
}
}
lab
- Faker API creates lots of random yet usable content
- wrap option in cowsay?
- npm i dom-to-image file-saver for exporting memes as images
- cors error in taking a url from protected websites