Förutom props har vi även state. state ska användas för att uppdatera UI:t och få en snabb applikation, samtidigt så är det lätt att man överanvänder state och krånglar till det. state ska oftast vara väldigt långt upp i applikationen. I vårt fall vill vi ha vårt state i App och sedan skicka ner värden till våra underkomponentener med hjälp av props. props ska vara immutable (får inte ändras), medan state får ändras.
Läs gärna: Lifting State Up @ React Docs
this.setState({}) exempel
//App.js
class App extends Component {
state = {
visible: true
}
handleClick = () => {
this.setState({ visible: !this.state.visible })
}
render(){
const name = this.state.visible ? <h1>Hello {this.state.name}! </h1> : null;
return(
<div>
{ name }
<button onClick={this.handleClick} >
Click me!
</button>
</div>
);
}skillnad mellan class och functional
// class
class Header extends Component {
render(){
return(
<h1>
{ this.props.title}
</h1>
);
}//Functional, no render method, just return. No `this`.
//props instead of this.props
function Header(props){
return(
<h1>
{ props.title}
</h1>
);
}- Skapa ett
<input>-fält i dinApp-komponent. Det behöver inte vara en egen komponent. - Skapa en ny metod i din klass som heter
handleChangeoch som tareventsom parameter. - Skapa en
onChangepå ditt input-fält och sätt så att metodenhandleChangeska köras varje gång inputfältet ändras. - Implementera så att
<input>-fältet uppdaterar värdetnameistate. MetodenhandleChangeska alltså kalla på funktionenthis.setState({})för att uppdatera värdet. - Gör sedan så att värdet av
nameskrivs ut någonstans på din sida. Du kan referera till värdet genom att skriva{this.state.name}. - Gör sedan så att det du skriver in i
this.state.nameskrivs ut baklänges 😎 Var ska detta göras? (tips, inte i själva statet) - Gör sedan så att värdet INTE skrivs ut om värdet innehåller ett
z.
Som vi sa behöver vi skicka state nedåt, så vi ska refaktorera vår applikation lite.
- Plocka ut ditt
<input>-fält och lägg det i en egen funktionell komponent:InputField.js. - Skicka ned metoden
handleChangesom enproptill denna komponent. - Få applikationen att fungera som den gjorde innan du delade upp den i flera delar.
- Använd
InputField-komponenten två gånger, ändra sedan värdet i ett av inputfälten och sedan det andra. Hur fungerar det?
- Skapa en knapp som är en egen komponent
Buttonoch själva knappen ska ha enonClick-funktion. - Skapa en funktion i
App.jssom uppdaterar en variabelstatemed 1 varje gång man klickar på den. Rendera ut dettastatenågonstans på din sida. - Skicka ner funktionen till din
Button-komponent. Alltså ska ett värde på sidan uppdateras med 1 varje gång vi klickar på knappen. Du måste ta nuvarande state och alltid öka det med 1.
Skapa en unik och trevlig webbshopupplevelse med state och props!
I ditt state ska du ha en array av produkter som heter t.ex. products. Varje produkt ska vara ett objekt som har ett namn och ett pris och gärna ett id. Rendera ut alla produkter i arrayen så att de visas på sidan i en lista eller i varsin <div>.
Varje produkt ska ha en knapp bredvid sig. När man trycker på knappen ska produkten läggas till i en annan array i ditt state som heter cart. Produkten ska alltså flyttas från ena arrayen i state till den andra när man trycker på knappen. Tips: du måste använda antingen Array.push eller Spread operator när du ska lägga till produkten, men inte inuti this.setState({}).
När produkten sedan ligger i din cart ska man kunna ta bort produkten också. I listan över produkter ska det alltså finnas en knapp till varje produkt som tar bort produkten ur this.state.cart.
Tips: du ska använda onClick på dina knappar och det behövs en funktion för att göra överföringen. Du ska skicka med vad som ska lagras i den andra arrayen som ett argument i din funktion som flyttar produkten från products till cart:
<button onClick={() => this.handleClick(product)} > Add To Cart </button>Vad kan man mer implementera? Hur många av varje produkt man vill köpa? Öka en räknare för varje produkt om man t.ex. vill köpa 2 av en produkt.
import React, { Component } from 'react';
class App extends Component {;
state = {
name: ''
}
handleChange = () => {
this.setState({ name: e.target.value });
}
render() {
//Check if the string includes the letter, conditional rendering!
let noZ = this.state.name.includes('z') ? 'No Z please!' : this.state.name;
return (
<div className="App">
<InputField handleChange={this.handleChange} value={this.state.name}/>
{ /* you can do this directly in render return or do it outside of the return */ }
<h1>Reverse: <br/> { this.state.name.split("").reverse().join("") }</h1>
<h1>{ noZ } </h1>
</div>
);
}
}
//Put this component in a separate file called `InputField.js`
class InputField extends Component {
render(){
return (
<input type="text"
name="name"
value={ this.props.value }
onChange={ this.props.handleChange } />
);
}
}
export default App;import React, { Component } from 'react';
import './App.css';
class App extends Component {
state = {
counter: 0
}
handleClick = () => {
//Take the current state and add 1 every time, the current state is
//always this.state.counter
this.setState({ counter: this.state.counter + 1 });
}
render() {
return (
<div className="App">
<Button handleClick={this.handleClick}/>
<h1>{ this.state.counter }</h1>
</div>
);
}
}
function Button(props) {
//onClick with big C!
return (
<button onClick={ props.handleClick }>
Click me!
</button>
);
}
export default App;class App extends Component {
state = {
products: [
"A thing",
"Ramen",
"A computer"
],
cart: []
};
}
addToCart = (product) => {
/* Spread the current values, the spread returns a NEW array,
* not bound to the old
*/
const newCart = [...this.state.cart, product];
this.setState({ cart: newCart });
}
render() {
//To hold the elements for the for-loop
const products =[];
//You can use a regular for loop to create the elements
for(let i = 0; i < this.state.products.length; i++){
products.push(
<div key={i}> {
this.state.products[i]}
<button onClick={ () => addToCart(this.state.products[i])}></button>
</div>);
}
// the Array.map-function makes this look more nice tho
const cart = this.state.cart.map( (item, index) => {
return <div key={index}> {item} </div>;
});
//Referencing the array in the return will automatically create the elements
//from the array
return (
<div className="App">
{ products }
{ cart }
</div>
);
}
}
export default App;