Edited and formatted by ericwm76
Eric's gist https://gist.github.com/ericwm76/e1204fc03f14af4429add8225ff55f71
# Creating a React App
1. In the terminal run: `npx create-react-app NAME-OF-APP`
2. Cd into the new directory: `cd NAME-OF-APP`
3. Run: `npm install`.
4. You can run `npm start` to see if the app was set up correctly.
## Setup Redux
1. `npm i redux react-redux redux-devtools-extension -S`
- redux - Allows us to have access to using Redux in our app.
- react-redux - Allows us to connect our react components to our Redux store.
- redux-devtools-extension - Useful for debugging in our devtools
2. In src/index.js
`import { Provider } from 'react-redux';`
- a component from react-redux that wraps our App component and allows each child component to be connected to the store
`import { createStore } from 'redux';`
- a function from Redux that uses the rootReducer to create the store
`import { composeWithDevTools } from 'redux-devtools-extension';`
- a method we brought in and can pass as an argument with createStore so that we have access to our devtools and can view our store.
`import { rootReducer } from './reducers';`
- our combined reducers to create our store
(order matters here)
```const store = createStore(rootReducer, composeWithDevTools())
ReactDOM.render(
,
document.getElementById('root')
);
```
3. In actions/index.js
-
4. In src/reducers/index.js
```
import { combineReducers } from 'redux';
import { todos } from './todos';
export const rootReducer = combineReducers({
todos: todos
});
```
**Where we define the properties that will exsits in our global store
5. `npm i redux-thunk -S`
## Setup Backend
1. Clone repo, not nested in project directory
2. Globally install nodemon. Runs the server.
3. `npm install nodemon -g`
4. cd into repo
5. Run `npm install`
6. Run `npm start`
7. Use Postman to checkout the data
## Setting Up Testing
1. Install Enzyme: `npm i enzyme -D`
2. Install Enzyme Adapter: `npm install enzyme-adapter-react-16 -D`
3. Inside of /src create setupTests.js: `touch src/setupTests.js`
4. Put the following 3 lines of code in setupTests.js
```
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
```
5. For snapshot testing, install Enzyme Wrappers: `npm install enzyme-to-json -D`
6. Add serializer to package.json:
```
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}
```
***Don't forget the comma!***
7. Add an extra line in App.js (just so there's a change in the file) and save. Then run `npm test` to check that the files are connected correctly.
8. Include the following lines as headers for all test files:
```
import React from 'react';
import { shallow } from 'enzyme';
import ClassName from './ClassName';
```
### Check Testing Coverage
```npm test -- --coverage --watchAll=false```
### Setting Up ESLint
1. ESLint is already built in with create-react-app. Installing another eslint will likely break things.
2. Add a script called `"lint": "eslint src/" in your package.json` (in the scripts object)
3. In your terminal, run: `npm run lint`
4. Turing [Mod3 Linter](https://github.com/turingschool-examples/javascript/blob/master/linters/module-3/linter-setup.md)
### Install SCSS/Sass
1. Run: `npm install node-sass --save`
2. Add variable file: `touch src/variables.scss`
3. Change all `.css` file extentions to `.scss`
- `index.css App.css` => `index.scss App.scss`
4. Remeber to update the file paths anywhere the style files are being imported
5. Add: `@import './src/variables.scss';` To any .scss files you want to uses variables
6. Format for creating variables: `$var-name: var-value;`
## propTypes
```npm install prop-types -S```
```import PropTypes from 'prop-types'```
```
Component.propTypes = {
prop1: PropTypes.array.isRequired,
prop2: PropTypes.any,
prop3: PropTypes.func.isRequired,
prop4: PropTypes.bool
prop5: PropTypes.string.isRequired,
prop6: PropTypes.number
}
```
## Router
1. `npm i react-router-dom -S`
2. In index.js
```
import { BrowserRouter } from 'react-router-dom'
const router = (
)
ReactDOM.render(router, document.getElementById('root'));
```
3. Import what is needed in components
`import { Route, NavLink, Link, Redirect, Switch} from 'react-router-dom'`
## TESTING
```
import { shallow } from 'enzyme';
```
```
wrapper = shallow (
```
```
expect(wrapper).toMatchSnapshot()
```
**Execution**
```
wrapper.instance().methodName('optionalArgument')
```
```
wrapper.instance().forceUpdate()
```
```
wrapper.find('button').simulate('click', optionalEvent)
```
```
wrapper.instance().setState({ prop: 'value', prop2: 'value2' })
```
```
wrapper.find('[name='thing']').simulate('change', mockThingEvent)
```
```
wrapper.find('button').at(3).simulate('click')
expect(mockWhatEverEvent).toHaveBeenCalledWith('argument/value')
```
**Mock Date.now()**
```
global.Date.now = jest.spyOn(global.Date, 'now').mockImplementation(() => 123)
```
Can assert that the value of Date.now() will be 123 or whatever is set as the return value.
**Mock e.preventDefault()**
Can be passed as arugments of event in other methods
```
const mockEvent = { preventDefault: jest.fn() }
```
**Mock Event**
```
const mockThingEvent = { target: { name: 'thing', value: 'Thing value' } }
```
**Expectation**
```
expect(wrapper.instance().handleChange).toHaveBeenCalledWith(mockThingEvent)
```
```
expect(wrapper.state('thing')).toEqual('Thing value') or expect(wrapper.state()).toEqual(expected)
```
```
expect(wrapper.instance().method).toHaveBeenCalled()
```
## Network Requests
**POST**
``` const options = {
method: 'POST',
body: JSON.stringify({
id: value,
prop: value,
}),
headers: {
'Content-Type': 'application/json'
}
}
return fetch('url', options)
.then(res => {
if(!res.ok) {
throw Error('Something is not right, try again later')
}
return res.json()})
```
**DELETE**
```
const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
return fetch(`url/${id}`, options)
.then(res => {
if(!res.ok) {
throw Error('Something is not right, try again later')
}
return getFetch();
}).catch(error => {
throw Error(error.message)
});
```