Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/components/Counter.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,36 @@ STEP 6:
This click handler needs to use 'setCount' to set the 'count' to be zero again.
*/

import React from 'react'; /* STEP 0 */
import React, {useState} from 'react'; /* STEP 0 */

export default function Counter() {
/* STEP 1 */

const [count, setCount] = useState(0);
const increment = () => {
/* STEP 4 */
setCount(count + 1);
};
const decrement = () => {
/* STEP 5 */
setCount(count - 1);
};
const reset = () => {
/* STEP 6 */
setCount(0);
};

const style = {
fontSize: '1.5em',
marginBottom: '0.3em',
color: 'royalblue', /* STEP 2 */
color: count % 2 === 0 ? 'royalblue' : "crimson", /* STEP 2 */
};

return (
<div className='widget-counter container'>
<h2>Counter</h2>
<div id='count' style={style}>
Number 0 is even {/* STEP 3 */}
{/* STEP 3: */}
Number {count} is {count % 2 === 0 ? "even" : "odd"} {/* STEP 3 */}
</div>
<div>
<button id='increment' onClick={increment}>Increment</button>
Expand All @@ -80,4 +84,4 @@ export default function Counter() {
</div>
</div>
);
}
}
11 changes: 7 additions & 4 deletions src/components/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,34 +34,37 @@ STEP 6:
We need to add an extra prop to the <input /> element like so: value={inputValue}
*/

import React from 'react'; /* STEP 0 */
import React, {useState} from 'react'; /* STEP 0 */

export default function Input() {
/* STEP 1 */
const [inputValue, setInputValue] = useState('');

const changeInput = evt => {
// When the input changes, its whole value can be found inside the event object.
// Log out the synthetic event object 'evt' and see for yourself.
const { value } = evt.target;

/* STEP 4 */
setInputValue(value);
};
const reset = () => {
/* STEP 5 */
setInputValue("");
};

const style = {
fontSize: '1.5em',
marginBottom: '0.3em',
color: 'royalblue', /* STEP 2 */
color: inputValue.length > 10 ? 'crimson' : 'royalblue', /* STEP 2 */
};

return (
<div className='widget-input container'>
<h2>Input</h2>
<div id='output' style={style}></div> {/* STEP 3 */}
<div id='output' style={style}>{inputValue.toUpperCase()}</div> {/* STEP 3 */}
<div>
<input id='input' type='text' onChange={changeInput} /> {/* STEP 6 */}
<input id='input' type='text' onChange={changeInput} value={inputValue}/> {/* STEP 6 */}
<button id='resetInput' onClick={reset}>Reset</button>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions src/components/Moods.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,39 @@ STEPS 4, 5, 6:
Inside these click handlers set the correct mood, using 'setMood' and the variables below the imports.
*/

import React from 'react'; /* STEP 0 */
import React, {useState} from 'react'; /* STEP 0 */

const initialMood = 'Not sure how I feel';
const happyMood = 'Quite happy!';
const sadMood = 'Rather sad';

export default function Moods() {
/* STEP 1 */
const [mood, setMood] = useState(initialMood);

const makeHappy = () => {
/* STEP 4 */
setMood(happyMood);
};
const makeSad = () => {
/* STEP 5 */
setMood(sadMood);
};
const reset = () => {
/* STEP 6 */
setMood(initialMood);
};

const style = {
fontSize: '1.5em',
marginBottom: '0.3em',
color: 'crimson', /* STEP 2 */
color: mood === happyMood ? 'royalblue' : 'crimson', /* STEP 2 */
};

return (
<div className='widget-moods container'>
<h2>Moods</h2>
<div id='mood' style={style}>Not sure how I feel</div> {/* STEP 3 */}
<div id='mood' style={style}>{mood}</div> {/* STEP 3 */}
<div>
<button id='makeHappy' onClick={makeHappy}>Make Happy</button>
<button id='makeSad' onClick={makeSad}>Make Sad</button>
Expand Down
23 changes: 17 additions & 6 deletions src/components/Programmers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ We can only feature one awesome programmer at a time.
Find comments below to help you along.
*/

import React from 'react';
import React, {useState} from 'react';

// Use this variable ONLY to initialize a slice of state!
// There is something in the JSX right now breaking this rule...
Expand All @@ -27,19 +27,30 @@ export const listOfAwesome = [
export default function Programmers() {
// We'll have to use the state hook twice, as we need two slices of state.
// The programmers list on the one hand, and the id of the featured programmer on the other.
const [programmers, setProgrammers] = useState(listOfAwesome);
const [featured, setFeatured] = useState(null);

const getNameOfFeatured = () => {
// Leave this for last!
// This is NOT an event handler but a helper function. See its usage inside the JSX.
// It's going to utilize both slices of state to return the _name_ of the featured dev.
// The beauty of closures is that we can "see" both slices of state from this region
// of the program, without needing to inject the information through arguments.

// for (let i = 0; i < programmers.length; i++) {
// if (programmers[i].id === featured) {
// return programmers[i].name;
// }
// }

const programmerObject = programmers.find(programmer => programmer.id === featured);
return programmerObject.name;
};

const style = {
fontSize: '1.5em',
marginTop: '0.5em',
color: 'royalblue', // 🤔 color turns to gold, when celebrating
color: featured ? 'gold' : 'royalblue', // 🤔 color turns to gold, when celebrating
};

return (
Expand All @@ -50,9 +61,9 @@ export default function Programmers() {
/* Nasty bug! We should map over a slice of state, instead of 'listOfAwesome'.
We might think: "it works, though!" But if the list of programmers is not state,
we could never add or edit programmers in the future. The list would be a static thing." */
listOfAwesome.map(dev =>
programmers.map(dev =>
<div className='programmer' key={dev.id}>
{dev.name} <button onClick={() => { /* in here set the featured id to be dev.id */ }}>Feature</button>
{dev.name} <button onClick={() => { setFeatured(dev.id) }}>Feature</button>
</div>
)
}
Expand All @@ -62,11 +73,11 @@ export default function Programmers() {
// Ternaries are fantastic to render "one thing or the other" depending on the "truthiness" of something.
// Pseudo-code: if the currently featured id is truthy render text 1, otherwise render text 2.
// Replace the hard-coded false with the correct variable.
false
featured
? `🎉 Let's celebrate ${getNameOfFeatured()}! 🥳`
: 'Pick an awesome programmer'
}
</div>
</div>
);
}
}
77 changes: 71 additions & 6 deletions src/components/Spinner.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,89 @@ STEP 4:
Do you remember the operator we use to do "not"?
*/

import React from 'react'; /* STEP 0 */
import React, {useState} from 'react'; /* STEP 0 */

export default function Spinner() {
/* STEP 1 */

/* STEP 1 */
const [spinnerOn, setSpinnerOn] = useState(true);
const toggleSpinner = () => {
/* STEP 4 */
setSpinnerOn(!spinnerOn);
};

return (
<div className='widget-spinner container'>
<h2>Spinner</h2>
{
true && <div id='spinner' className='spinner'>--+--</div> /* STEP 2 */
spinnerOn && <div id='spinner' className='spinner'>--+--</div> /* STEP 2 */
}
<button id='toggleSpinner' onClick={toggleSpinner}>
Hide Spinner {/* STEP 3 */}
{spinnerOn ? "Hide" : "Show"} Spinner {/* STEP 3 */}
</button>
</div>
);
}
}

/*
// SPINNER Instructions

// Watch this short video:
// https://tk-assets.lambdaschool.com/38201164-4df9-4c89-923b-5325dc72124d_spinner.gif

// How many slices of state do you think are necessary to act as "sources of truth" for all
// the things that change in this widget? Give it some thought before continuing reading!

// Our first impulse might be to say 2 different states:
// - Whether the spinner is visible or not (perhaps this could be a boolean).
// - Whether the text of the button reads "Show Spinner" or "Hide Spinner".

// But a single slice of state is all that's needed here: whether spinner is on or not.
// The text of the button can be derived from the value of that one slice of state.

// STEP 0:
// Start by studying the component below, and importing the state hook.

// STEP 1:
// Create a 'spinnerOn', 'setSpinnerOn' pair of variables using the state hook.
// The 'spinnerOn' slice should be initialized to true so the spinner is visible on page load.

// STEP 2:
// This is called a logical expression. If the expressions on both sides of the '&&' are truthy,
// the one on the right becomes the value of the whole line. If an expression on either side of the '&&'
// is falsy, the one on the left becomes the value of the whole line. It's a neat little trick to render
// a React element (in this case the spinner) conditionally: only if the variable on the left is truthy.

// Replace the hard-coded 'true' with the variable that keeps track of whether spinner is on or not.

// STEP 3:
// Use a ternary expression inside the text of the button, to render "Hide" or "Show" depending on the value of 'spinnerOn'.

// STEP 4:
// This click handler needs to toggle the spinner by setting "whether on" to be the opposite of what it currently is.
// Do you remember the operator we use to do "not"?
// */

// import React, {useState} from 'react'; /* STEP 0 */

// export default function Spinner() {
// /* STEP 1 */
// const [spinnerOn, setSpinnerOn] = useState(true);
// const toggleSpinner = () => {
// /* STEP 4 */
// setSpinnerOn(!spinnerOn);
// };

// return (
// <div className='widget-spinner container'>
// <h2>Spinner</h2>
// {
// spinnerOn && <div id='spinner' className='spinner'>--+--</div> /* STEP 2 */
// }
// {/* STEP 3:
// Use a ternary expression inside the text of the button, to render "Hide" or "Show" depending on the value of 'spinnerOn'. */}
// <button id='toggleSpinner' onClick={toggleSpinner}>
// {spinnerOn ? "Hide" : "Show"} Spinner {/* STEP 3 */}
// </button>
// </div>
// );
// }
Loading