Click button once click just render text - javascript

How to create a button than once click the button will render just text by using react hook
const WelcomeButton = (props) => {
const[welcomeBtn, setwelcomeBtn] = useState()
const handelClick = () => {
if() {
retun <p>Hi John</p>
}
}
return (
<div>
<button onClick={handelClick}> Welcome </button>
</div>
)
;
};

I suggest using a state that tracks that the button has been clicked, and update/toggle this value in the handleClick callback. Conditionally render either the button or the welcome text based on this state.
const WelcomeButton = (props) => {
// initial state true to show button
const [welcomeBtn, setWelcomeBtn] = React.useState(true);
const handelClick = () => {
// toggle false to hide button and display welcome message
setWelcomeBtn(false);
};
return (
<div>
{welcomeBtn ? (
<button onClick={handelClick}> Welcome </button>
) : (
<p>Hi John</p>
)}
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(
<WelcomeButton />,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />

Related

Passing component to another component, props doesn't show up - react js

I'm trying to pass the 'Username' component directly into the 'Comment' component, like I did with the 'ProfilePicture' component, but only the '#' symbol shows up and not the username. Please help, also thanks in advance!
//component
const ProfilePicture = (props) => {
return (
<div>
<img
className="ProfilePicture"
src={props.user.pfpUrl}
alt={props.user.name}
height={50}
width={50}
/>
</div>
)
};
// username component
const Username = (props) => {
return (
<div>
<p>#{props.user.username}</p>
</div>
)
};
// user's comment
const comment = {
username: "guest",
image: {
name: "Default Profile Image",
pfpUrl: 'https://static.vecteezy.com/system/resources/thumbnails/009/292/244/small/default-avatar-icon-of-social-media-user-vector.jpg'
}
}
const Comment = (props) => {
return (
<div>
<ProfilePicture user={props.image} />
<Username user={props.username} />
</div>
)
}
ReactDOM.render(
<Comment image={comment.image} username={comment.username} />,
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">
<!-- This element's contents will be replaced with your component. -->
</div>
You need to access it like props.user in your Username component
//component
const ProfilePicture = (props) => {
return (
<div>
<img
className="ProfilePicture"
src={props.user.pfpUrl}
alt={props.user.name}
height={50}
width={50}
/>
</div>
)
};
// username component
const Username = (props) => {
return (
<div>
<p>#{props.user}</p> // YOU are passing user as a prop to username component
</div>
)
};
// user's comment
const comment = {
username: "guest",
image: {
name: "Default Profile Image",
pfpUrl: 'https://static.vecteezy.com/system/resources/thumbnails/009/292/244/small/default-avatar-icon-of-social-media-user-vector.jpg'
}
}
const Comment = (props) => {
return (
<div>
<ProfilePicture user={props.image} />
<Username user={props.username} />
</div>
)
}
ReactDOM.render(
<Comment image={comment.image} username={comment.username} />,
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">
<!-- This element's contents will be replaced with your component. -->
</div>
Change the <Username> in your Comment component to read:
<Username user={{username:props.username}} />
This matches the way you are retrieving the username later.

State becomes empty

Counter File
import React, { useState } from "react";
import Widget from "./widget";
const Counter = () => {
const [form, setForm] = useState(<></>)
const [text, setText] = useState("")
const onCounterChange =() => {
setText(text)
}
const formLoad =() =>{
setForm(
<Widget
onCounterChange={onCounterChange}
children={
<input type="text" onChange={(e) =>{
setText(e.target.value)
}}/>
}
/>
)
}
return (
<div>
{text}
<button onClick={formLoad}>
load widget
</button>
{form}
</div>
)
}
export default Counter
Widget File
import React from 'react'
export default function Widget(props) {
return (
<div className="buttons">
{props.children}
<button onClick={props.onCounterChange}>Save</button>
</div>
)
}
I have created small text printing page . for some purpose I have added children in a diff component and handling widget in a state , so when I try to change the data , text state is changing but when I click save text state becomes empty
As I mentioned in my comment putting a component in state probably isn't the best way of approaching this. Instead I would have a boolean state that allows you to toggle the component on/off.
const { useState } = React;
function Example() {
const [ showWidget, setShowWidget ] = useState(false);
const [ text, setText ] = useState('');
function handleChange(e) {
setText(e.target.value);
}
function handleClick() {
setShowWidget(!showWidget);
}
function handleSave() {
console.log(`Saved state: ${text}`);
}
return (
<div>
<p className="text">Current state: {text}</p>
<button onClick={handleClick}>
Load widget
</button>
{showWidget && (
<Widget>
<input
type="text"
onChange={handleChange}
/>
<button onClick={handleSave}>Save</button>
</Widget>
)}
</div>
);
}
function Widget({ children }) {
return <div className="widget">{children}</div>;
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
.widget { margin-top: 1em; }
.text { margin-bottom: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Why is the (memoized) child component re-rendering?

I have two React functional components: C1 and C2. C2 is nested inside C1:
const C2 = () => {
console.log("C2 Render");
return (
<div>I am Component 2</div>
);
};
const C1 = () => {
const [text, setText] = useState("Hello");
const MC2 = React.memo(C2, () => true);
return (
<div className="box">
<h1>The Button</h1>
<button
onClick={() => {
setText(`${text} b`);
}}
className="button">
Click me
</button>
<div>
{text}
</div>
<MC2 />
</div>
);
}
CodePen here.
The problem
I know that a component gets re-rendered under different situations. Among those is the one when the parent re-renders.
That is why I am using a memoized component around C2. But still I can see the console displaying "C2 Render" every time I click the button.
Why?
C1 rerender because of state chnage, so your memoized component is redeclared every time.
just wrap C2 in a React.memo() & you would not see the rerenders
const MC2 = React.memo(() => {
console.log("C2 Render");
return (
<div>I am Component 2</div>
);
}, () => true);
or if you want to memoize only one useCase put it outside the C1 component and have that component memoized:
const C2 = () => {
console.log("C2 Render");
return (
<div>I am Component 2</div>
);
};
const MC2 = React.memo(C2, () => true);
& used it like this:
const C1 = () => {
const [text, setText] = useState("Hello");
return (
<div className="box">
<h1>The Button</h1>
<button
onClick={() => {
setText(`${text} b`);
}}
className="button">
Click me
</button>
<div>
{text}
</div>
<MC2 />
</div>
);
}

How do you focus and select an input when it loads?

I was unable to find good answer to the question of focusing and selecting an input element on load; initially I just used a useRef(), set it as the ref and then on component load (useEffect(,[])) I would ref.current.focus() / ref.current.select(). But input's built in autoFocus and onFocus are much simpler solutions.
In other words, consider the following code snippet where we want to focus on the input when you press the button (it doesn't work here)
// Get hook functions (specific for use with stackoverflow code snippet)
const { useState } = React;
const Example = ({title}) => {
// hook that keeps track of the editing state
const [editing, setEditing] = useState(false);
// switch to input when button is pressed
const InputComponent = () => {
if (!editing) {
return ( <span>click for input</span>)
}
else {
return ( <input /> )
}
}
return (
<div>
<p>{title}</p>
<p>{InputComponent()}</p>
<button onClick={() => setEditing(!editing)}>
Click me
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="The goal is to have the input automatically focused" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Now, if we use references
const { useState, useRef, useEffect } = React;
const Example = ({title}) => {
const [editing, setEditing] = useState(false);
// useRef for a reference to the input
const inputRef = useRef();
const InputComponent = () => {
if (!editing) {
return ( <span>click for input</span>)
}
else {
// set the ref as a reference to the input
return ( <input ref={inputRef}/> )
}
}
// when editing updates, run this code
useEffect(() => {
// when editing is true, focus the input
if (editing) {inputRef.current.focus()}
}, [editing])
return (
<div>
<p>{title}</p>
<p>{InputComponent()}</p>
<button onClick={() => setEditing(!editing)}>
Click me
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="The goal is to have the input automatically focused" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
further if you want to select the value of the input when it's focused you can do the following:
const { useState, useRef, useEffect } = React;
const Example = ({title}) => {
const [editing, setEditing] = useState(false);
// define a state variable for the input value
const [inputValue, setValue] = useState("value of the input");
const inputRef = useRef();
const InputComponent = () => {
if (!editing) {
return ( <span>click for input</span>)
}
else {
return (
<input
ref={inputRef}
// define the value of the input
value={inputValue}
// when the input is changed, update the state variable
onChange={(event) => setValue(event.target.value)}
/>
)
}
}
useEffect(() => {
if (editing) {
inputRef.current.focus();
// focus and select the value of the input
inputRef.current.select();
}
}, [editing])
return (
<div>
<p>{title}</p>
<p>{InputComponent()}</p>
<button onClick={() => setEditing(!editing)}>
Click me
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="The goal is to have the input automatically focused" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
This methodology would allow you to set some base value of the input (like a stylized way of representing the value, and then when the user clicks that stylize value it begins editing).
This solution is well and good, but it's bulky and requires that you pass references down to the component in some cases, and is just generally not clean. So is there a better solution? yes....
Here's a simplified version that will accomplish the same effect but much simpler
const { useState, useRef, useEffect } = React;
const Example = ({title}) => {
const [editing, setEditing] = useState(false);
const [inputValue, setValue] = useState("value of the input");
// no need for a reference
const InputComponent = () => {
if (!editing) {
return ( <span>click for input</span>)
}
else {
return (
<input
// don't need to set an input reference
onChange={(event) => setValue(event.target.value)}
value={inputValue}
onFocus={(event) => event.target.select()} // selects the value on load
autoFocus // focuses on load
/>
)
}
}
// no need for a useEffect
return (
<div>
<p>{title}</p>
<p>{InputComponent()}</p>
<button onClick={() => setEditing(!editing)}>
Click me
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="The goal is to have the input automatically focused" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
There you go, a much faster, simpler, and easier to understand implementation of focusing on an input on load. Cheers! :)

Filter a list based on Input

const App = () => {
const [searchTerm, setSearchTerm] = React.useState('');
const stories = [
...
];
const handleSearch = event => {
setSearchTerm(event.target.value);
};
const searchStories = stories.filter((story) => {
return story.title.includes(searchTerm);
})
return (
<div>
<h1>My Hacker Stories</h1>
<Search onSearch={handleSearch}/>
<hr />
<List list={searchStories}/>
</div>
);
};
const Search = (props) =>{
return (
<div>
<label htmlFor="search"><strong>Search:</strong></label> { ' '}
<input id='search' type='text' onChange={props.onSearch}/>
</div>
);
};
const List = ({list}) =>
list.map((item) =>
(
<div key={item.objectID}>
<span>
<a href={item.url}>{item.title}</a>
</span>
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span>
</div>
)
)
I am trying to filter the List Component based on the search input. It's working unless if I put a search term in the input box. When I try to search an item, List is empty, nothing is showing, it's empty List, however, there is no error showing.
I've change your code a little to produce a runnable snippet which you can change back to your code,
just need to add another state for searchStories and use useEffect for filtering when searchTerm changes like this:
*Click the Run Code Snippet and type h so you can see how filter works
const App = () => {
const [searchTerm, setSearchTerm] = React.useState("");
const [searchStories, setSearchStories] = React.useState([]);
const stories = ["hello", "hi", "bye", "have a good day"];
const handleSearch = event => {
setSearchTerm(event.target.value);
};
React.useEffect(() => {
setSearchStories(
stories.filter(story => {
return story.includes(searchTerm);
})
);
}, [searchTerm]);
return (
<div>
<h1>My Hacker Stories</h1>
<Search onSearch={handleSearch} />
<hr />
<List list={searchStories} />
</div>
);
};
const Search = props => {
return (
<div>
<label htmlFor="search">
<strong>Search:</strong>
</label>{" "}
<input id="search" type="text" onChange={props.onSearch} />
</div>
);
};
const List = ({ list }) =>
list.map(item => (
<div key={item}>
{item}
{/* <span>
<a href={item.url}>{item.title}</a>
</span>
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span> */}
</div>
));
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
The filter function checks whether the searchTerm is present in our story item's title, but it's still too opinionated about the letter case. If we search for "react", there is no filtered "React" story in your rendered list. To fix this problem, we have to lower case the story's title and the searchTerm.
const App = () => {
...
const searchedStories = stories.filter(function(story) {
return story.title
.toLowerCase()
.includes(searchTerm.toLowerCase());
});
...
};

Categories

Resources