Reputation: 173
I'm new to react and I'm trying to learn it. So far, with tutorials and so on, I made a computer with a light and day mode. I want to add a div on the right side where text will appear based on conditions, like: if the output is over 9000, a message with appear like "its over 9000!" and so on. I want to add multiple text sentences based on different conditions. I've tried but I keep getting errors like undefined, state is a const, etc. What's the best way to do this using useState?
//imports
export const actionsPossible = {
add_: "add",
operation_: "operation",
clear_: "clear",
delete_: "delete",
equal_: "equal",
}
function reducer(state, { type, payload }) {
switch (type) {
case actionsPossible.add_: //add
if (state.overwrite) {
return {
...state,
currentOperand: payload.digit,
overwrite: false,
}
}
if (payload.digit === "." && state.currentOperand == null) {
return state
}
if (payload.digit === "0" && state.currentOperand === "0") {
return state
}
if (payload.digit === "." && state.currentOperand.includes(".")) {
return state
}
return {
...state,
currentOperand: `${state.currentOperand || ""}${payload.digit}`,
}
case actionsPossible.clear_: //clear
{
return {}
}
case actionsPossible.operation_: //choosing operation
if (state.currentOperand == null && state.previousOperand == null) {
return state
}
if (state.currentOperand == null) {
return {
...state,
Operation: payload.Operation,
}
}
if (state.previousOperand == null) {
return {
...state,
Operation: payload.Operation,
previousOperand: state.currentOperand,
currentOperand: null,
}
}
return {
...state,
previousOperand: evaluate(state),
currentOperand: null,
operation_: payload.operation_,
}
case actionsPossible.equal_: //equal
{
if (state.Operation == null || state.currentOperand == null || state.previousOperand == null) {
return state
}
return {
...state,
overwrite: true,
previousOperand: null,
currentOperand: evaluate(state),
Operation: null,
}
}
case actionsPossible.delete_: //delete
{
if (state.overwrite) {
return {
...state,
overwrite: false,
currentOperand: null
}
}
if (state.currentOperand == null) {
return state
}
if (state.currentOperand.length === 1) {
return {
...state,
currentOperand: null
}
}
return {
...state,
currentOperand: state.currentOperand.slice(0, -1)
}
}
default: return state //default case
}
}
function evaluate({ currentOperand, previousOperand, Operation }) {
const previous = parseFloat(previousOperand)
const current = parseFloat(currentOperand)
if (isNaN(previous) || isNaN(current)) return ""
let computation = ""
switch (Operation) {
case "+":
computation = previous + current
break
case "-":
computation = previous - current
break
case "*":
computation = previous * current
break
case "÷":
computation = previous / current
break
default:
return
}
return computation.toString()
}
})
function formatOperand(operand) {
// format so 1000 can be 1,000
}
function App() {
//const [Trivia, setTrivia] = useState("")
const [theme, setTheme] = useState("light")
const [{ currentOperand, previousOperand, Operation }, dispatch] = useReducer(reducer, {})
const toggleTheme = () => {
setTheme((curr) => (curr === "light" ? "dark" : "light"))
}
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<div id={theme}>
<div className="calculator-grid">
<div className="output">
<div className="previous-operand">{formatOperand(previousOperand)} {Operation}</div>
<div className="current-operand">{formatOperand(currentOperand)}</div>
</div>
<button className="span-two" onClick={() => dispatch({ type: actionsPossible.clear_ })}>AC</button>
<button onClick={() => dispatch({ type: actionsPossible.delete_ })}>DEL</button>
<OperationButton Operation="÷" dispatch={dispatch} />
<DigitButton digit="1" dispatch={dispatch} />
<DigitButton digit="2" dispatch={dispatch} />
<DigitButton digit="3" dispatch={dispatch} />
<OperationButton Operation="*" dispatch={dispatch} />
<DigitButton digit="4" dispatch={dispatch} />
<DigitButton digit="5" dispatch={dispatch} />
<DigitButton digit="6" dispatch={dispatch} />
<OperationButton Operation="+" dispatch={dispatch} />
<DigitButton digit="7" dispatch={dispatch} />
<DigitButton digit="8" dispatch={dispatch} />
<DigitButton digit="9" dispatch={dispatch} />
<OperationButton Operation="-" dispatch={dispatch} />
<DigitButton digit="." dispatch={dispatch} />
<DigitButton digit="0" dispatch={dispatch} />
<button className="span-two" onClick={() => dispatch({ type: actionsPossible.equal_ })}>=</button>
{/*----------------------------------TOGGLE BTN--------------------------------*/}
//toggle button code, not important
{/*----------------------------------TRIVIA--------------------------------*/}
<div className="count">
<h1>Random Trivia</h1>
<h4>{Trivia}</h4>
{/* <h4>{Trivia2}</h4> */}
{/* <h4>{Trivia3}</h4> */}
{/* <h4>{Trivia4}</h4> */}
</div>
</div>
</ThemeContext.Provider>
);
}
export default App;
Upvotes: 0
Views: 1107
Reputation: 804
Basic conditional rendering follow this syntax
const Component = ({ ... }) => {
...
return (
<div>
{Boolean(value) && <ComponentToRenderIfTrue />}
</div>
);
}
Then a very basic example of having several possible trivia would look like
const Component = ({ ... }) => {
...
return (
<div>
{currentOperand === 1 && <span>Trivia 1</span>} // only rendered if currentOperand === 1 else ignored
{currentOperand === 2 && <span>Trivia 2</span>} // only rendered if currentOperand === 2 else ignored
{currentOperand === 3 && <span>Trivia 3</span>} // only rendered if currentOperand === 3 else ignored
{currentOperand === 4 && <span>Trivia 4</span>} // etc
{currentOperand === 5 && <span>Trivia 5</span>}
</div>
);
}
Another less verbose way would be to simply compute a trivia value using useMemo
const Component = ({ ... }) => {
...
const trivia = useMemo(() => {
switch (operand) {
case 1: return 'Trivia 1';
case 2: return 'Trivia 2';
case 3: return 'Trivia 3';
case 4: return 'Trivia 4';
default:
return null;
}
}, [operand]);
return (
<div>
{Boolean(trivia) && <span>{trivia}</span>}
</div>
);
}
The more precise explanation of how conditional rendering work is that when you provide a boolean value in the rendering, the React engine will actually ignore it
const Component = () => {
return (
<div>
{false} // will be ignored by react engine
</div>
);
}
In js true && 'hello world'
simply resolve to the string 'hello world'
while false && 'hello world'
resolve to the boolean false
Then
const Component = () => {
return (
<div>
{true && <span>hello world</span>}
</div>
);
}
is actually the same as
const Component = () => {
return (
<div>
<span>hello world</span>
</div>
);
}
If you put things together you should understand how {Boolean(value) && <Component/>}
might either be ignored by react engine if Boolean(value)
is false or render if Boolean(value)
is true
Upvotes: 1