I'm trying to make a simple app that counts the number of times the button has been clicked. I read this is a good first question in JS interviews.
"Ask the candidate to build a click counter using any popular framework (React preferred in 2020). This ridiculously simple app has one job: keep track of how many times the user has clicked the button during the current session. No storage. No network I/O. Just count clicks. It is intentionally ridiculously simple"
My first instinct would be to use hooks, but the question wants the programmer to do it without using storage which I believe includes using state.
import React from 'react';
import './App.css';
function App() {
let count=0;
const add=()=>{
debugger;
count++;
}
return (
<header className="App-header">
<button onClick={()=>add()}>click me</button>
{count}
</header>
);
}
export default App;
Here is what I tried. Using debugger I can see count does go up but the changes aren't showing on the page. Any advice would be appreciated.
React is a JS library so we can use pure js:
function App() {
return (
<div className="App">
<h1 id="c">0</h1>
<button
onClick={() => {
let c = document.getElementById("c");
c.innerHTML = parseInt(c.textContent)+1;
}}
>
+
</button>
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
The reason your code doesn't produce the expected result is that React doesn't update the dom unless it sees that an update is necessary, i.e., because the state of the component changed.
So, in your case, the component only gets rendered once, when the value of count is 0. If you want to React to re-render the component and show you the new value, you'll have to trigger that with a state change. Alternatively you can follow cybercoder's solution, which actually opts out of React by supplying its own innerHTML.
Related
I have a certain component named ThemeDoc inside this component there is a context, localStorage, hooks, maps and whatnot, but in the end I get the value of the hooks inside a component named SideBar. I decided that there is no need to demonstrate the contents of the ThemeDoc component in order not to complicate my code and question, but I will attach a link of my project on the github if you want you can see GitHub Project. So as I just mentioned, I get the value of the hooks from the ThemeDoc component for the SideBar component, they look like this
const {SideBarValue, SideBarWallpaperValue, SideBarColor} = React.useContext(CounterContext);
const [SideBarTheme, SetSideBarTheme] = SideBarValue;
const [SideBarBackground] = SideBarWallpaperValue;
const [SideBarColorTheme, SetSideBarColor] = SideBarColor;
These values are used to change the color of the SideBar.
<div style={{background: SideBarTheme}}>
...
</div>
It all looks like this
Please see there are two values for SideBarTheme and SideBarColorTheme, SideBarTheme changes the background of the site to a gradient and the SideBarColorTheme only changes the SideBar color. As you can see I successfully applied the SideBarTheme value inside jsx and everything works fine for me
<div style={{background: SideBarTheme}}>
...
</div>
But I can’t use SideBarColorTheme, I don’t know how to do it, here is my full-fledged code if you need to tell me I will provide the ThemeDoc component
SideBar.jsx
function SideBar(props) {
const {someValue} = useContext(SideBarContext);
const {SideBarValue, SideBarColor} = React.useContext(CounterContext);
const [SideBarTheme, SetSideBarTheme] = SideBarValue;
const [SideBarColorTheme, SetSideBarColor] = SideBarColor;
return (
<div style={{background: SideBarTheme, backdropFilter: `blur(${someValue}px)`}}>
...
</div>
);
}
This is prob a super easy question but, I want to add components to a grid with react and jquery.
gridGame is a black 100px by 100px square and I want to add items into it. Im using rows (a variable) witch is a number from 1-9 to and sumbing it in to the gridGame-${rows} as seen here,so it can auto update the correct row to join. value should be: gridGame-${row} (what ever number row is from 1-9) and then I want to add a component inside gridGame called <Test /.> (witch is declared up-top in unseen parts of the code).
The function below has jquery that I thought would work in this situation:
function = (rows) => {
console.log(`joining ${rows}`)
let value= $(`#gridGame-${rows}`);
value.append("<Test />");
value.css("background-color", 'brown');
$(".create-coinflip-box").css("display", "none");
}
The css background change works but the value.append does not display the react component.
Here is the React Component inside the <Test /.>:
import React from 'react';
import StatusIcon from './img/image.png';
import Player1Icon from './img/image.png'
class newGame extends React.Component {
render() {
return(
<div>
HELLO
</div>
);
}
}
export default newGame;
I honestly have 0 idea on how this doesn't work.
Thanks for the help :)
This answer was from David in the comments. The problem for me was I was trying to render a component through a button and not the actual render its self.
The solution is to instead make the button change the state witch Updates the React DOM. Then just have a if statement that checks the state then display the component.
His comment explains much better and fixed the problem for me.
I am new to React and working on an app that changes navbar layout and some other details according to screen size, but renders the same responsive content inside. The <MyContent /> itself can vary according to the route or tab the user is visiting.
function App() {
const isMobile = useSomeHookToDetectIfMobile();
return (
{isMobile
? <MobileWrapper><MyContent /></MobileWrapper>
: <DesktopWrapper><MyContent /></DesktopWrapper>
}
);
}
The thing is, if the user resizes the window, when changing layout all the state inside <MyContent /> is lost and reset. What would be the most React way to maintain it on resize? Keep in mind that the shape of the state of <MyContent /> can vary according to what components it is displaying, so I don't think lifting state up is the way to go. Also its state only concerns itself, so I don't think it belongs farther up the component chain. I think I am missing some key point about the problem or coming at it the wrong way. Any help would be appreciated.
In this case, a simple local variable to keep the rendered content before the condition would be enough. That way, React can keep track of it and then it's always the same instance.
function App() {
const isMobile = useSomeHookToDetectIfMobile();
const content = <MyContent />;
return (
{isMobile
? <MobileWrapper>{content}</MobileWrapper>
: <DesktopWrapper>{content}</DesktopWrapper>
}
);
}
i'm taking SveleteJS for a test drive and got stuck
Made a Dashboard component and inside that component, i placed a Whiteboard component:
<script>
import Whiteboard from "./Whiteboard.svelte";
export let name;
</script>
<div class="box part-of-dashboard">
<Whiteboard lines={[]} />
</div>
Whitebord.svelte:
<script>
export let lines = [];
export function addLine() {
lines.push("blah");
console.log(lines);
}
</script>
<div style="background-color:red">
{#each lines as line}
<div>
{line}
</div>
{/each}
</div>
<div>
<button on:click={addLine}>
Add Line
</button>
</div>
When i click the button, the console.log triggers and i can see the lines increasing in size, but i don't see it being rendered on the page, just the empty red div wrapping it.
I've tried adding $: to various places, but i'm not yet sure where it should be used and where it shouldn't be used, not that it was making a difference.
How do i get that #each to render a list of divs (and also, what is the correct way to pass in data from the on:click, doing {addLine('blah')} executes that addLine on page load)?
So, this kind of goes against what one might expect, but Svelte does not detect [].push() as mutating the state of the array variable. This is why the console log shows the variable being updated, but Svelte's rendering does not respond.
After doing a little digging, I found several threads (1, 2) that point this out, and clarify that this is true for calling methods on any object.
EDIT: This is also now called out explicitly in the docs / tutorials - see "Updating Arrays and Objects"
One of the easiest solutions (per the linked threads and docs) is to simply re-assign the variable value to itself; Svelte will pick that up and re-render. So, in your scenario, all I had to do to get your code to work was replace this:
export function addLine() {
lines.push("blah");
console.log(lines);
}
With:
export function addLine() {
lines.push("blah");
lines = lines;
console.log(lines);
}
I'm having trouble finding relevant documentation on how to remove UI components when using react. For example, there's a login form. The user clicks submit and now the form should be removed from the screen. How do I do this?
I've found unmountComponentAtNode, but that can only be invoked at the parent level. Am I supposed to have a parent node that is aware of all child state and loads them conditionally? Should all children have an "isHidden" attribute which renders the dom as hidden if true?
This must be basic but I don't see this in the react js tutorials. I found this stackoverflow post (react.js: removing a component) is this really the pattern? It kind of makes sense but it means that a large app will likely have an extremely complex Application parent class that manages maps of application state based on configuration.
It seems like i need to start defining application state as named maps. For example:
BaseApp: showHeader=true;showContent=true;
LoginState: showBaseApp=true;showLoginForm=true;
LoggedInState: showBaseApp=true;showFeed=true;
At any moment we would have to update all state maps and call the base class render method...
In my opinion your question isn't about removing component but about showing the right component. And yes - it can be done with a component state but with Flux/Redux store/reducer as well.
In your example with a login form after click on "Submit" we can change local state for the component and show another text like "The request was sent blah-blah-blah" or another component.
But you can do this by extracting component's local state to a store/reducer and it'll be work better in relatively big app. Nevertheless, it's really up to you where you want to store state.
I like to use a hide prop like so.
class AppCtrlRender extends React.Component {
render() {
let page = this.state.appState.currentPage;
let hideAbout = (page != 'about');
let hideHome = (page != 'home');
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
<div id='allPageSty' style={allPageSty}>
<AboutPage hide={hideAbout} />
<HomePage hide={hideHome} />
</div>
</div>
);
}
}
export default class AboutPage extends React.Component {
render() {
if (this.props.hide) return null;
let aTime = (new Cache()).time.toString();
return (
<div style={AboutPageSty}>
React 0.14 ReFlux used for app state. This is the About Page.
<NavMenu /><br/><br/>
{aTime}
</div>
);
}
}