https://courses.wesbos.com/ | https://reactforbeginners.com/ | https://github.com/wesbos/React-For-Beginners-Starter-Files
Version: 20220729 | Status: Completed
cd
(and then drag folder into terminal) to navigation to folder quickly<div id="main">
is the mounting point for React Appimport { render } from 'react-dom';
to render the code as DOM/HTML<div id="#main">
)./components/StorePicker.js
class StorePicker extends React.Component {
render() {
return <p>Hello</p>
}
}
render(<StorePicker/>,document.querySelector('#main'));
components
folder./index.js
import React from 'react';
import { render } from 'react-dom';
import StorePicker from './components/StorePicker';
render(<StorePicker/>,document.querySelector('#main'));
./components/StorePicker.js
import React from 'react';
class StorePicker extends React.Component {
render() {
return <p>Hello</p>
}
}
export default StorePicker
return (
All the HTML code you need
)
class
because it is a reserved word/name in JavaScript - use className
return (
<form>
</form>
)
This is not:
return (
<form>
</form>
<p>
</p>
)
return (
<React.Fragment>
<form>
</form>
<p>
</p>
</React.Fragment>
)
or
return (
<>
<form>
</form>
<p>
</p>
</>
)
img
input
hr
br
{/* comment */}
when in JSX, curly brackets means “I’m doing JavaScript”import './css/style.css';
import React from 'react';
import Header from './Header';
import Order from './Order';
import Inventory from './Inventory';
class App extends React.Component {
render() {
/* comment */
return (
<div className="catch-of-the-day">
<div className="menu">
<Header />
</div>
<Order />
<Inventory />
</div>
);
}
}
export default App;
props
, with is like an attribute for a componentin `App.js`
<Header tagline="Fresh Seafood Market"/>
in `Header.js`
<h3 className="tagline-class">{this.props.tagline}</h3>
this
refers to the component{ }
Console
and press $r
Console
and press $0
class Header extends React.Component {
render () {
return (
{/* code */}
);
}
}
You can use Stateless/Dumb/Pure/Simple Component:
const Header = props = > {
return (
{/* code....note, no this, so {props.tagline} */}
);
}
const Header = props = > ( /* implicit return method */
{/* code....note, no this, so {props.tagline} */}
)
const Header = ({tagline,age}) = > ( /* implicit return with destructuring */
{/* code....note, no this, so {tagline} */}
)
index.js
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router';
import StorePicker from './components/StorePicker';
import App from './components/App';
import NotFound from './components/NotFound';
const Router = () => {
return (
<BrowserRouter>
<Switch>
{/* For the root */}
<Route exact pattern='/' component={StorePicker} />
{/* For anything '/store' */}
<Route path='/store/:storeId' component={App} />
{/* For anything '/store' */}
<Route component={NotFound} />
</Switch>
</BrowserRouter>
)
}
render(<Router/>,document.querySelector('#main'));
helpers.js
file
export function getFunName() {
}
And in the place to call the helper function,
import { getFunName } from '../helpers';
render
is bound to the component, so refering this
references the componentthis
does not reference the componentimport React from 'react';
import { getFunName} from "../helpers";
class StorePicker extends React.Component {
handleClick() {
console.log("clicked");
}
render() {
return (
<form>
<button onclick={this.handleClick}>Click</button> {/* don't use this.handleClick() or it will run on mount */}
<input
type="text"
placeholder="Store Name"
defaultValue={getFunName()}
/>
<button type="submit"></button
</form>
)
}
}
export default StorePicker
ref
to access an item, you don’t wanna touch DOM. here are two deprecated ways:<input
type="text"
placeholder="Store Name"
defaultValue={getFunName()}
ref={myInput} {/*this is deprecated, don't use that - FYI only*/
/>
<input
type="text"
placeholder="Store Name"
defaultValue={getFunName()}
ref={(myInput) => this.myInput = myInput} {/*this is deprecated, don't use that - FYI only*/
/>
import React from 'react';
import { getFunName} from "../helpers";
class StorePicker extends React.Component {
constructor() {
super();
this.goToStore = this.goToStore.bind(this);
}
myInput = React.createRef();
goToStore(event) {
event.preventDefault(); /*stopped form from submitting*/
console.log(this.myInput.value); /*grab text from box, this is the component only if goToStore is arrow function*/
}
render() {
return (
<form onSubmit={this.goToStore}>
<input
type="text"
placeholder="Store Name"
defaultValue={getFunName()}
ref={this.myInput}
/>
<button type="submit"></button
</form>
)
}
}
export default StorePicker
import React from 'react';
import { getFunName} from "../helpers";
class StorePicker extends React.Component {
myInput = React.createRef();
goToStore = event => {
event.preventDefault(); /*stopped form from submitting*/
console.log(this.myInput.value.value); /*grab text from box, this is the component only if goToStore is arrow function*/
/*this.myInput.value is React, this.myInput.value.value is JavaScript */
}
render() {
return (
<form onSubmit={this.goToStore}>
<input
type="text"
placeholder="Store Name"
defaultValue={getFunName()}
ref={this.myInput}
/>
<button type="submit"></button
</form>
)
}
}
export default StorePicker
...
goToStore = event => {
event.preventDefault(); /*stopped form from submitting*/
const storeName = this.myInput.value.value; /*grab text from box, this is the component only if goToStore is arrow function*/
/*this.myInput.value is React, this.myInput.value.value is JavaScript */
this.props.history.push(`/store/${storeName}`); /*this.props is taking props from parent component, which is React Router */
}
...
App.js
class App extends React.Component {
state = { //set initial state
fishes: {},
order: {}
}
addFish = fish => {
const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
this.setState({ fishes }); /* 3. Update state with new fish */
};
render () {
return (
<div>
<Inventory addFish={this.addFish} /> {/* addFish is passed down */}
</div>
);
}
}
export default App;
Inventory.js
<AddFishForm addFish={this.props.addFish} />
AddFishForm.js
class addFishForm extends React.Component {
nameRef = React.createRef();
priceRef = React.createRef();
createFish = (event) => {
event.preventDefault();
const fish = {
name: this.nameRef.value.value,
price: parseFloat(this.nameRef.value.value), //float to store everything in cents
};
this.props.addFish(fish);
event.currentTarget.reset(); //reset form
}
render () {
return (
<form className='fish-edit' onSubmit={this.createFish}>
<input name="name" ref={this.nameRef} type="text" placeholder="Name" />
<input name="price" ref={this.priceRef} type="text" placeholder="Price" />
<button type='submit'>+ Add Fish</button>
</form>
);
}
}
export default addFishForm;
Inventory.js
<button onClick={this.props.loadSampleFishes}>Load Sample Fishes</button>
We load in a fishes object from sample-fishes.js
In App.js
import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes
class App extends React.Component {
state = { //set initial state
fishes: {},
order: {}
}
addFish = fish => {
const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
this.setState({ fishes }); /* 3. Update state with new fish */
};
loadSamples = () => {
this.setState({ fishes: sampleFishes });
};
render () {
return (
<div className='catch-of-the-day'>
<Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
</div>
);
}
}
Object.keys(object)
will map over objectthis.state.fishes
)import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes
class App extends React.Component {
state = { //set initial state
fishes: {},
order: {}
}
addFish = fish => {
const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
this.setState({ fishes }); /* 3. Update state with new fish */
};
loadSamples = () => {
this.setState({ fishes: sampleFishes });
};
render () {
return (
<div className='catch-of-the-day'>
<Header />
<ul className="fishes">
{
Object
.keys(this.state.fishes) //turn object into array
.map(key => <Fish key={key} details={this.state.fishes[key]}/>)
}
</ul>
<Order />
<Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
</div>
);
}
}
Fish.js
as Simple/Pure/Dumb/Stateless Component
import React from 'react';
const Fish = ({ key, details }) => {
const { image, name, price, desc, status } = details;
return (
<li className="menu-fish">
<img src={image} alt={name} />
<h3>{name}</h3>
<span className="price">{formatPrice(price)}</span>
<span className="description">{desc}</span>
</li>
);
}
export default Fish;
index
. key
is for the component, index
is for you.App.js
import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes
class App extends React.Component {
state = { //set initial state
fishes: {},
order: {}
}
// addFish function
// loadSamples function
addToOrder = key = {
const order = {...this.state.order}; //copy order
order[key] = order[key] + 1 || 1; //Add to order or, if it doesn't exist, add 1
this.setState({ order }); //update State
}
render () {
return (
<div className='catch-of-the-day'>
<Header />
<ul className="fishes">
{
Object
.keys(this.state.fishes) //turn object into array
.map(key => <Fish key={key} index={index} details={this.state.fishes[key]} addToOrder={this.addToOrder}/>)
}
</ul>
<Order />
<Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
</div>
);
}
}
import React from 'react';
const Fish = ({ details, addToOrder, index }) => {
handleClick = () => {
addToOrder(index);
}
const { image, name, price, desc, status } = details;
const isAvailable = status === 'availabe';
return (
<li className="menu-fish">
<img src={image} alt={name} />
<h3>{name}</h3>
<span className="price">{formatPrice(price)}</span>
<span className="description">{desc}</span>
<button disabled={!isAvailable} onClick={this.handeClick}>{ (isAvailable) ? "Add to Order" : "Sold Out!" }</button>
{/* OR do it as a one liner */}
<button disabled={!isAvailable} onClick={() => addToOrder(index)}>{ (isAvailable) ? "Add to Order" : "Sold Out!" }</button>
</li>
);
}
export default Fish;
<Order {...this.state}>
Reduce takes in data and takes in a tally
base
so it can be imported elsewherecomponentWillMount
- when component is mounted, you can do ajax request/connect to rebase/sync component state with firebase statecomponentDidMount () {
const { params } = this.props.match
this.ref = base.syncState(`${params.storeId}/fishes`, {
context: this,
state: 'fishes'
});
}
componentWillUnmount () {
base.removeBinding(this.ref);
}
componentDidUpdate
- invoked before props or state changescomponentDidUpdate () {
localStorage.setItem(this.props.match.params.stordId,JSON.stringify(this.state.order);
}
JSON.stringify
to convert object
to string
componentDidMount () {
const { params } = this.props.match;
/* new */
const localStorageRef = localStorage.getItem(params.storeId);
if (localStorageRef) {
this.setState({ order: JSON.parse(localStorageRef) });
} /* new end */
this.ref = base.syncState(`${params.storeId}/fishes`, {
context: this,
state: 'fishes'
});
}
JSON.parse
to convert string
to object
import { TransitionGroup, CSSTransition } from "react-transition-group";
<TransitionGroup component="ul"> replacing <ul>
<CSSTransition classNames="order" key="{key}" timeout=> WRAPS <li>
import PropTypes from "prop-types";
class Fish extends React.Component {
static propTypes = {
tagline: PropTypes.string.isRequired,
functionA : PropTypes.func,
details: PropTypes.shape({
image: PropTypes.string,
price: PropTypes.number
})
}
...
import PropTypes from "prop-types";
const Header = props => (
...
);
Header.propTypes = {
tagline: PropTypes.string.isRequired,
functionA : PropTypes.func,
details: PropTypes.shape({
image: PropTypes.string,
price: PropTypes.number
})
}
npm run build
npm i -g now
now -v
npm i -g serve
Replace start
with dev
, create new start
url
package.json
"start": "serve --single ./build"
now
will deploy to server
Use alias to deploy to same url
npm i -g netlify
netlify -v
netlify deploy
Q: Yes
A: Build
/* /index.html 200`
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]