https://help.github.com/en/articles/changing-a-remotes-url
https://github.com/turingschool-examples/webpack-starter-kit
$ git remote -v
> origin git@github.com:USERNAME/REPOSITORY.git (fetch)
> origin git@github.com:USERNAME/REPOSITORY.git (push)
$ git remote set-url origin https://github.com/USERNAME/REPOSITORY.git
Verify that the remote URL has changed.
$ git remote -v
> origin https://github.com/USERNAME/REPOSITORY.git (fetch)
> origin https://github.com/USERNAME/REPOSITORY.git (push)
git push -u origin master
- In the terminal run
npx create-react-app NAMEOFYOURAPP
- Cd into the new directory:
cd NAMEOFYOURAPP
- Run
npm install
. - You can run
npm start
to see if the app was set up correctly.
Setting Up Testing
- Install enzyme:
npm i enzyme -D
- Install enzyme-adapter-react-16:
npm install enzyme-adapter-react-16 -D
- Inside of /src create setupTests.js:
touch src/setupTests.js
- 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() });
- For snapshot testing, install enzyme-to-json
npm install enzyme-to-json -D
- In package.json, add the following lines of code:
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}
Don't forget the comma!
- 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. - Include the following lines as headers for all test files:
import React from 'react';
import { shallow } from 'enzyme';
import ClassName from './ClassName';
git clone [https://github.com/ REPO NAME THEY GIVE US]
cd [CD INTO REPO]
npm install nodemon -g
npm i
npm start
Note that the frontend should be running on localhost:3000
and the backend should be running on localhost:3001
.
Clone down the backend repo - but NOT inside your existing frontend repository!
https://frontend.turing.io/lessons/module-3/react-router-v4.html
npm i react-router-dom -S
index.js
import { BrowserRouter } from 'react-router-dom'
const router = (
<BrowserRouter>
<App />
</BrowserRouter>
)
ReactDOM.render(router, document.getElementById('root'));
In neccessary files:
import { Route, Link } from 'react-router-dom'
<Route path="/" render={() => <Component />} />
<Route exact path="/" render={() => <Component prop={this.prop} />} />
<Link to="/" className="link"><h5>BACK</h5></Link>
Setup Redirect
Used when a change needs to happen based on state
Import: Redirect
Need: setRedirect and renderRedirect functions
import { Redirect } from 'react-router-dom';
export class ComponentName extends Component {
constructor() {
super();
this.state = {
redirect: false
};
}
handleSubmit = (e) => {
const { actionName } = this.props;
e.preventDefault();
actionName(this.state);
this.setRedirect();
}
setRedirect = () => {
this.setState({
redirect: true,
});
}
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to="/confirmation" />;
}
}
render() {
return (
<form className="ComponentName">
<input
className="class-name"
name="name"
type="text"
placeholder="Enter Name"
value={this.state.name}
onChange={this.handleChange}
/>
{this.renderRedirect()}
<button disabled={!this.state.formReady} type="button" className="class-name" onClick={this.handleSubmit}>SUBMIT BOOKING</button>
<Link to="/" className="link"><h5>BACK</h5></Link>
</form>
);
}
}
}
Class Component
import React, { Component } from 'react';
import Classname from './Classname';
import Funcname from '../Funcname/Funcname';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
key: value
}
}
method = () => {
console.log('run something')
}
render() {
return (
<div>
Return something
</div>
)
}
}
export default App;
Functional Component
import React from 'react';
import anotherFuncname from '../anotherFuncname/anotherFuncname';
import './Funcname.css';
const Funcname = () => {
return (
<div>
Return something
</div>
)
}
export default Funcname;
Form Functions needed
handleChange = event => {
this.setState({
[event.target.name]: event.target.value
})
}
submitNewData = event => {
event.preventDefault()
const newData = {
match key/value pairs of required data
}
this.props.funcFromApp(newData)
this.clearInputs()
}
clearInputs = () => {
this.setState({
key1: '',
key2: ''
})
}
Input Structure
<input
name=''
placeholder=''
value={this.state.key}
onChange={() => {}}
/>
setState
.then(ideas => this.setState({
ideas: ideas
}))
.then(ideas => this.setState({ ideas }))
this.setState({
value: key
})
setState Is Async
functionName = (parameter) => {
this.setState({
value: key
}, () => {
anotherFunctionName((parameter) => {
return something
}))
});
};
apiCalls
export const funcName = async(url) => {
const response = await fetch(url)
if(response.ok) {
const data = await response.json()
return data;
} else {
throw Error(response.statusText)
}
}
Snapshot Test
import React from 'react';
import { shallow } from 'enzyme';
import NameOfTested from './NameOfTested';
describe('NameOfTested', () => {
it('should', () => {
const wrapper = shallow(
<Component />
)
expect(wrapper).toMatchSnapshot();
})
})
Test Dynamic Changes Template
Setup - What do we need to do in order to render the component (aka shallow or mount). What data needs to be mocked?
Execution - Let’s run the command or simulate the action.
Expectation - This is where our assertion happens. After running our function, what did we expect to happen?
Update State Test
import React from 'react';
import ReactDOM from 'react-dom';
import { shallow } from 'enzyme';
import NameOfTested from './NameOfTested';
describe('NameOfTested', () => {
it('should', () => {
const wrapper = shallow(
<Component />
)
const mockData = ?
const expected = ?
// Expectation
expect(wrapper.state('stateKeyName')).toEqual([]);
// Execution
wrapper.instance().funcName(argumentName);
// Expectation
expect(wrapper.state('stateKeyName')).toEqual(expected);
})
})
Function Test
it('should change state based on an event', () => {
const mockFunction = jest.fn()
const wrapper = shallow(<
Component
submitUser={mockFunction}
/>)
const mockEvent = {
target: {
name: 'name', value: 'value'
}
}
wrapper.instance().handleChange(mockEvent)
expect(wrapper.state('name')).toEqual('value')
})
Simulate A Click Test
wrapper.instance().forceUpdate();
wrapper.find('element').simulate('click');
wrapper.find('element').at(0).simulate('click');
wrapper.find('button').simulate('click', mockEvent);
expect(mockFunction).toHaveBeenCalledWith(argument);
expect(wrapper.instance().resetInputs).toHaveBeenCalled();
Ex:
it('should run funcName on click', () => {
const mockFuncName = jest.fn();
const wrapper = shallow(
<Component
prop={look to parent to see what gets passed down}
prop={look to parent to see what gets passed down}
/>
)
wrapper.find('element').at(0).simulate('click');
expect(mockFuncName).toHaveBeenCalled();
});
apiCall Tests
import { fetchData } from './apiCalls';
describe('fetchData', () => {
const mockResponse = {
results: [{
key: 46286
},
{
key: 601365
}],
};
const mockUrl = 'https://www.address.com/...';
beforeEach(() => {
window.fetch = jest.fn().mockImplementation(() => Promise.resolve({
ok: true,
json: () => Promise.resolve(mockResponse),
}));
});
it('should fetch with the correct url', () => {
fetchData(mockUrl);
expect(window.fetch).toHaveBeenCalledWith(mockUrl);
});
it('should return an array of ?? (HAPPY)', () => {
fetchData(mockUrl)
.then((results) => expect(results).toEqual(mockResponse));
});
it('should return an error (SAD)', () => {
window.fetch = jest.fn().mockImplementation(() => Promise.resolve({
ok: false
}));
const mockUrl = 'https://www.address.com/...YOLO';
expect(fetchData(mockUrl)).rejects.toEqual(Error());
});
it('should return an error if the server is down', () => {
window.fetch = jest.fn().mockImplementation(() => ({
status: 500
}))
expect(fetchData()).rejects.toEqual(Error());
});
});
Mock A Function
const mockFunction = jest.fn();
Mock An Event
const mockEvent = {
preventDefault: jest.fn();
}
Mock Date.now()
global.Date.now = jest.fn().mockImplementation(() => 12345)
const expected = { title: '', description: '', id: 12345 };
Debug
console.log(wrapper.debug());
Verbose In package.json, under scripts, edit the "test" script:
"test": "react-scripts test --verbose"
Test Percentage Chart In Terminal
npm test -- --coverage --watchAll=false
componentDidMount() {
fetch('URL')
.then(response => response.json())
.then(data => this.setState({
key: data
}))
.catch(error => console.error(error))
}
addIdea = varName => {
const options = {
method: 'POST',
body: JSON.stringify(varName),
headers: {
'Content-Type': 'application/json'
}
};
fetch('URL', options)
.then(response => response.json())
.then(data => this.setState({
key: [...this.state.key, data]
}))
.catch(error => console.error(error))
}
removeIdea = id => {
const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
fetch(`URL/${id}`, options)
.then(() => fetch('URL'))
.then(response => response.json())
.then(data => this.setState({
key: data
}))
.catch(error => console.error(error));
}
}
export const fetchData = async (url) => {
const response = await fetch()
if (response.ok) {
const data = await response.json()
} else {
throw Error(response.statusText)
}
}
import PropTypes from 'prop-types';
Component.propTypes = {
title: PropTypes.string.isRequired
}
https://reactjs.org/docs/typechecking-with-proptypes.html#react.proptypes
ideas: [...this.state.key, newVariableElement]
const Component = ({ isFavorite }) => {
const favoriteClass = isFavorite ? 'favorite' : 'card'
return (
<section className={favoriteClass}>
</section>
)
}
Setting Up ESLint
- ESLint is already built in with create-react-app. Installing another eslint will likely break things.
- Add a script called
"lint": "eslint src/" in your package.json
(in the scripts object) - In your terminal, run:
npm run lint
https://github.com/turingschool-examples/javascript/blob/master/linters/module-3/linter-setup.md
- In terminal,
npm i eslint-config-airbnb -D
- In package.json,
// update the scripts and eslintConfig portions of your package.json to match below
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js --ignore-pattern node_modules/ --ignore-pattern src/serviceWorker.js"
},
"eslintConfig": {
"extends": [
"react-app",
"airbnb"
]
},
- In terminal
eslint src/**/*.js --ignore-pattern node_modules/ --ignore-pattern src/serviceWorker.js
- If want to fix,
eslint src --fix
Install SCSS/Sass
- Run:
npm install node-sass --save
- Add variable file:
touch src/variables.scss
- Change all
.css
file extentions to.scss
index.css App.css
=>index.scss App.scss
- Remeber to update the file paths anywhere the style files are being imported
- Add:
@import './src/variables.scss';
To any .scss files you want to uses variables - Format for creating variables:
$var-name: var-value;
Any time .toHaveBeenCalledWIth()
is called it needs to be used with a mock function so it can be spied on.
Background Image in CSS
body {
background-image: url('../images/bright-colors-daylight-2742812.jpg');
background-size: cover;
background-position: 50% 30%;
background-repeat: no-repeat;
height: 100vh;
width: 100%;
font-family: $heading-font;
margin: 0;
}
Dont Test Certain Things
package.json
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"collectCoverageFrom": [
"src/**/{!(serviceWorker),}.js",
"!src/index.js",
"!src/reducers/index.js"
]
}
How To Pass Match
In App
<Route exact path="/shuttle/:trail" render={(match) => <ShuttleForm match={match}/>} />
In Component
<Link to={`/shuttle/${name}`}><button className="Trail-btn" id={name}>BOOK</button></Link>
How To Disable Button/check for values in inputs
this.state = {
disabled: true
};
formReady = () => {
this.setState({ disabled: true })
if (this.state.name !== '' && this.state.ingredients !== []) {
this.setState({ disabled: false })
} else {
this.setState({ disabled: true })
}
}
<button disabled={this.state.disabled} onClick={e => this.handleSubmit(e)}>
error message
<p>{ this.state.disabled ? 'PLEASE FILL OUT NAME' : null }</p>
How To Console Log In A Render
{console.log(this.props.match)}
Preparation
- Checkout your
master
branch and double-check to make sure it is up-to-date and there is nothing needed to be committed at this point - Navigate to the root of your project directory
- Open your project in your text editor
- Double-check that all image tags in your HTML have the
src
attribute have./
to start the path, e.gsrc="./images/turing-logo.png"
Required Steps
In the package.json
file, within the "repository"
object, edit the "url"
value to be "git+https://github.com/USERNAME/REPONAME.git"
where USERNAME and REPONAME are replaced with your GitHub username and your repository name, respectively
OR
In the package.json
file, add the line: "homepage": "http://USERNAME.github.io/REPONAME",
where USERNAME and REPONAME are replaced with your GitHub username and your repository name, respectively
OR Just "homepage": ".",
- Add these two lines to the
scripts
section of thepackage.json
file:
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
- In the terminal, run
npm install --save-dev gh-pages
- You should see these lines of JSON added to your
package.json
file:
"devDependencies": {
"gh-pages": "^1.1.0"
}
- Run
npm run build
in the command line - Run
npm run deploy
in the command line
All of this will create a gh-pages
branch in your repo with the contents from the build
directory.
If you go to the GitHub pages site (http://USERNAME.github.io/REPONAME) in a minute, you should see your app! If not, check out the console to see what errors you're getting and troubleshoot from there.
Deploying with React Router
- npm install --save gh-pages
- “homepage”: “.“,
- “predeploy”: “npm run build”, “deploy”: “gh-pages -d build”
- import { HashRouter as Router } from ‘react-router-dom’ in
index.js
file and change to just<Router></Router>
- run npm run and build commands, done, go check GitHub Pages.
When You Make New Changes
If you make new changes to your master
branch, GitHub Pages doesn't automatically know about these changes, and your site won't be up-to-date. You need to update the gh-pages
branch to see those changes live on GitHub Pages. Here is how to update and keep everything in sync:
- After you're done making changes, checkout your
master
branch and double-check to make sure it is up-to-date and there is nothing needed to be committed at this point - Run
npm run build
in the command line - Run
npm run deploy
in the command line
#Postman
body, raw, json
React I: The What and The Why https://frontend.turing.io/lessons/module-3/react-i.html
React II: The How, building IdeaBox https://frontend.turing.io/lessons/module-3/react-ii.html
React III: Workshop Ideabox With A Backend https://frontend.turing.io/lessons/module-3/react-iii.html
Unit Testing React Components https://frontend.turing.io/lessons/module-3/unit-testing-react.html
Get Your Site On GH Pages https://github.com/turingschool-examples/webpack-starter-kit/blob/master/gh-pages-procedure.md
Webpack Starter Kit https://github.com/turingschool-examples/webpack-starter-kit
Network Request GET/POST Requests https://frontend.turing.io/lessons/module-3/network-request-exercises.html
All Lessons https://frontend.turing.io/lessons/