I have index.js file where I have rendered the App component .
Index.js file
ReactDOM.render(<App />, document.getElementById('root'));
Below is the code for SettingContainer.js file where I have SettingContainer component. I have a button on click of it I need to rerender <SettingContainer value="10" /> But It doesn't render with defaultvalues.
SettingContainer.js file:
import React from 'react';
const SettingContainer = (props) => {
const [state, setState] = React.useState({
currentValue: props.value
});
const handleChange = (event) => {
setState({ currentValue: event.target.value });
};
return (
<React.Fragment>
<input type='text' value={state.currentValue} onChange={handleChange} />
</React.Fragment>
)
};
export default SettingContainer;
Below is the code for the App.js file where I have App component.
App.js file
const handleClick = () => {
ReactDOM.render(<SettingContainer value="10" />, document.getElementById('divHello'));
};
const App = () => {
return (
<>
<div id="divHello">
<SettingContainer value="10" />
</div>
<button onClick={handleClick}>Button</button>
</>
);
};
export default App;
Actually, your issue comes back to your mindset, you should change your thoughts about ReactJS. you should have an Index container like below:
const Index = () => {
const [isRender, renderSettingContainer] = useState(false);
return (
<>
{isRender && (
<SettingContainer />
)}
<App onClick={renderSettingContainer}>
</>;
);
};
Then, pass the onClick function from props to the App like below:
const App = ({ onClick }) => (
<>
Hello Friends
<div id="divHello">
</div>
<button onClick={onClick}>Button</button>
</>
);
Also, there is no need to use ReactDOM twice, so write it like below:
ReactDOM.render(<Index />, document.getElementById('root'));
If you have any questions, write a comment, definitely, I will answer and will change my answer.
Hint: the <></> is just like <React.Fragment></React.Fragment> with less code and better performance, based on Dan Abramov idea.
Use conditional rendering, on press button set value to display Hello component.
const Hello = () => (<p>Hello</p>)
Then in App set value to true on button press.
const App = () => {
const [displayHello, setDisplayHello] = useState(false);
const handleClick = () => {
setDisplayHello(!displayHello)
};
return (
<React.Fragment>
Hello Friends
<div id="divHello">
</div>
{displayHello && <Hello />}
<button onClick={handleClick}>Button</button>
</React.Fragment>
);
};
// Get a hook function
const {useState} = React;
const Hello = () => (<p style={{ backgroundColor: 'green', color: 'white'}}>Hi from Hello Component</p>)
const App = () => {
const [displayHello, setDisplayHello] = useState(false);
const handleClick = () => {
setDisplayHello(!displayHello)
};
return (
<React.Fragment>
Hello Friends
<div id="divHello">
</div>
{displayHello && <Hello />}
<button onClick={handleClick}>Button</button>
</React.Fragment>
);
};
// Render it
ReactDOM.render(
<App />,
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>
Related
I need to make class active on when box is clicked using React hooks.
The box is not a simple div element, but is dynamically loaded from an array.
I have problem with this funtion:
const changeClassName = (props) => {
return props.className.replace("box active");
};
This doesn't change the className property.
Codepen link
Full code:
import React, { useState } from "https://cdn.skypack.dev/react#17.0.1";
import ReactDOM from "https://cdn.skypack.dev/react-dom#17.0.1"
const sounds = [
{
key: "A",
mp3: "https://audiodeploy.netlify.app/8%20El-Mu'minun,%20115-116.mp3",
},
{
key: "B",
mp3: "https://audiodeploy.netlify.app/8%20El-Mu'minun,%20115-116.mp3",
}
];
const App = () => {
const [keys, setKeys] = useState([
"1","2"
]);
const [active, setActive]=useState(false);
return (
<>
<span id="text"></span>
<div id="display" className="display">
{sounds.map((sound, id) => {
return <Box text={sound.key} audio={sound.mp3} />;
})}
</div>
</>
);
};
const changeClassName=(props)=>{
return(
props.className.replace("box active") // this doesn't change the className
)
}
const playSound = (audioRef,props) => {
audioRef.current.play();
console.log(props.text);
if(props.text==='A'||props.text=='B')
ReactDOM.render(
<>
<p> Then did you think that We created you uselessly and that to Us you would not be returned?"</p>
<p>So exalted is Allāh, the Sovereign, the Truth; there is no deity except Him, Lord of the Noble Throne.</p>
<p>[Quran, 23:115-116]</p>
</>
, document.getElementById('text'));
changeClassName(props);
};
const Box = (props) => {
const audioRef = React.useRef();
return (
<div className="box" onClick={() => playSound(audioRef,props)}>
{props.text}
<audio
src={props.audio}
ref={audioRef}
/>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
Could you please help me to fix this?
This should do the work for the active part, but you may need to clean that up a little bit
https://codepen.io/quentinbenyahia/pen/yLqaEvv
const App = () => {
const [isActive, setIsActive] = useState(false);
const playSound = (audioRef,id) => {
audioRef.current.play();
ReactDOM.render(
<>
<p> Then did you think that We created you uselessly and that to Us you would not be returned?"</p>
<p>So exalted is Allāh, the Sovereign, the Truth; there is no deity except Him, Lord of the Noble Throne.</p>
<p>[Quran, 23:115-116]</p>
</>
, document.getElementById('text'));
setIsActive(id)
};
return (
<>
<span id="text"></span>
<div id="display" className="display">
{sounds.map((sound, id) => {
return <Box playSound={(audioRef) => { playSound(audioRef, id ) }} isActive={id === isActive} text={sound.key} audio={sound.mp3} />;
})}
</div>
</>
);
};
const Box = (props) => {
const audioRef = React.useRef();
return (
<div className={props.isActive ? "box active": "box"} onClick={() => props.playSound(audioRef)}>
{props.text}
<audio
src={props.audio}
ref={audioRef}
/>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
you can follow these steps:
1- const [isActive , setIsActive] = useState(false)
2- const changeClassName=(props)=>{
setIsActive(true)
}
3- <div className={isActive ? "box active": "box"} onClick={() => playSound(audioRef,props)}>
{props.text}
<audio
src={props.audio}
ref={audioRef}
/>
</div>
I have two components, the parent and child. Currently I have these codes below. But unfortunately it returns an error:
TypeError: Cannot read property 'click' of null
For some reasons I want when button is click the Item component also will be click. But these codes below produces an error above. Anyone does know how to achieve it?
import React, { useRef } from 'react';
const App = (props) => {
const itemRef = useRef(null);
return (
<div>
{dynamicBoolean ? (
<button onClick={() => itemRef.current.click()}>
click item
</button>
) : (
//more codes here
<Item ref={itemRef} />
)}
</div>
);
};
export default App;
Child component would look like below (demonstration purposes, the code is very lengthly)
import React from 'react';
const Item = (props) => {
return (
<div>
//some design here
</div>
);
};
export default Item;
You need useRef and you have to forward this ref to the Item component.
import React, { forwardRef, useRef } from 'react';
const Item = forwardRef((props, ref) => {
return <li {...props}
onClick={() => alert('clicked on Item')}
ref={ref} >MyItem</li>
})
const App = (props) => {
const itemRef = useRef(null);
return (
<div>
<button onClick={() => itemRef.current.click()}>
click item
</button>
<Item ref={itemRef} />
</div>
);
};
export default App;
import React, { createRef } from "react";
const Hello = (props) => {
const itemRef = createRef();
const hello = () => {
itemRef.current.click();
};
return (
<div>
<button onClick={() => hello()}>click item</button>
<Item ref={itemRef} />
</div>
);
};
const Item = React.forwardRef((props, ref) => {
const myClick = () => {
console.log("this is clicked");
};
return (
<button ref={ref} className="FancyButton" onClick={myClick}>
{props.children}
</button>
);
});
export default Hello;
I'm trying to create a simple component that displays a group of buttons such that when one of the buttons is pressed, the parent knows the ID of that button. I have written some code, but I'm stuck as to the final step to identify which of the buttons is pressed. Any help would be appreciated. Thanks!
function GroupofButtons(props) {
const groupofBtns = [];
props.btns.forEach((btn) => {
groupofBtns.push(<button id={btn} value={btn} key={btn} onClick={() => props.onClick()}>{btn}</button>)
}
);
return(
<>
{groupofBtns}
</>
)
}
function App() {
// How can the console show the id of the button that was pressed
const handleClick = () => console.log("pressed");
const btn_typs = [1,2,3,];
return (
<>Press a button!
<div>
<GroupofButtons btns={btn_typs} onClick={() => handleClick()}/>
</div>
</>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Something like this:
import React from "react";
import "./styles.css";
const btn_typs = [1, 2, 3];
export default function App() {
const handleClick = (e) => {
console.log(e.target.name);
};
return (
<>
Press a button!
<div>
<GroupofButtons btns={btn_typs} handleClick={handleClick} />
</div>
</>
);
}
function GroupofButtons(props) {
return props.btns.map((btn, i) => (
<button name={btn} key={i} onClick={props.handleClick}>
{btn}
</button>
));
}
Heres the codepen: https://codesandbox.io/s/suspicious-firefly-czvct?file=/src/App.js
I want to copy the div content on button click.
import React from 'react';
const App = () => {
const copyCode = () => {
//TODO
}
const data = "www.test.com";
const srcCode = `<script src=${data}></script>`;
return (
<>
<div>
{srcCode}
</div>
<button onClick={copyCode}>
Copy
</button>
</>
);
}
export default App;
This could be simple using react-copy-to-clipboard library
const data = "www.test.com";
const srcCode = `<script src=${data}></script>`;
return (
<>
<div>{srcCode}</div>
<br />
<CopyToClipboard text={srcCode} onCopy={() => alert("copied")}>
<button>Copy</button>
</CopyToClipboard>
</>
);
Codesandbox for demo
I need to access the location of a child component. For what I understand, to access the child properties, I need to use useImperativeHandle to add the child API to its ref. Moreover, I need to use forwardRef to transmit the reference from the parent to the child. So I did this:
const Text = React.forwardRef(({ onClick }, ref) => {
const componentAPI = {};
componentAPI.getLocation = () => {
return ref.current.getBoundingClientRect ? ref.current.getBoundingClientRect() : 'nope'
};
React.useImperativeHandle(ref, () => componentAPI);
return (<button onClick={onClick} ref={ref}>Press Me</button>);
});
Text.displayName = "Text";
const App = () => {
const ref = React.createRef();
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.current.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
<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="app"></div>
As you can see, the ref doesn't have the getBoundingClientRect property, but if I do this it will work as expected:
const App = () => {
const ref = React.createRef();
const [value, setValue] = React.useState(null)
return (<div>
<button ref={ref} onClick={() => setValue(ref.current.getBoundingClientRect()) } ref={ref}>Press Me</button>
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
<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="app"></div>
So what is wrong with my understanding of useImperativeHanedle and forwardRef?
To use useImperativeHandle you need to work with another ref instance like so:
const Text = React.forwardRef(({ onClick }, ref) => {
const buttonRef = React.useRef();
React.useImperativeHandle(
ref,
() => ({
getLocation: () => buttonRef.current.getBoundingClientRect()
}),
[buttonRef]
);
return (
<button onClick={onClick} ref={buttonRef}>
Press Me
</button>
);
});
If you want your logic to be valid (using the same forwarded ref), this will work:
const Text = React.forwardRef(({ onClick }, ref) => {
React.useEffect(() => {
ref.current.getLocation = ref.current.getBoundingClientRect;
}, [ref]);
return (
<button onClick={onClick} ref={ref}>
Press Me
</button>
);
});
Why your example doesn't work?
Because ref.current.getBoundingClientRect not available in a moment of assigning it in useImperativeHandle (try logging it) because you actually overridden the button's ref with useImperativeHandle (Check Text3 in sandbox, the ref.current value has getLocation assigned after the mount).
As shown in docs(maybe not understandable enough), the child component itself should have a different ref, and by useImperativeHandle you can define a function mapping forwardedRef to child ref:
import React from 'react'
import ReactDOM from 'react-dom'
const Text = React.forwardRef(({ onClick }, ref) => {
const buttonRef = React.useRef() // create a new ref for button
const componentAPI = {};
componentAPI.getLocation = () => {
return buttonRef.current.getBoundingClientRect ? buttonRef.current.getBoundingClientRect() : 'nope' // use buttonRef here
};
React.useImperativeHandle(ref, () => componentAPI); // this maps ref to buttonRef now
return (<button onClick={onClick} ref={buttonRef}>Press Me</button>); // set buttonRef
});
Text.displayName = "Text";
const App = () => {
const ref = React.useRef();
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.current.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
I just wanted to add this answer to show how things can become easier when removing useless overcontrol...
const Text = React.forwardRef(({ onClick }, ref) => {
ref.getLocation = () => ref.current && ref.current.getBoundingClientRect()
return (<button onClick={onClick} ref={ref}>Press Me</button>);
});
Text.displayName = "Text";
function App() {
const ref = { current: null };
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
}
ReactDOM.render(<App />, document.querySelector("#app"))
<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="app"></div>
In the code above, we just use forwardRef and attach the child API to it's ref, which seems very natural in the end, and very userfriendly.
The only thing that would prevent you using this is that React.createRef makes a call to Object.preventExtension() (thanks for making my life harder...), so the hack is to use { current: null } instead of Object.createRef() (which is basically the same).