const {useRef, useState} = React;
function List(){
const renderCount = useRef(0);
console.log('<List /> is rendered', ++renderCount.current);
const [isClicked, setIsClicked] = useState(false);
const toggle = () => setIsClicked(!isClicked)
return (
<div>
<ButtonA onClick={toggle} isClicked={isClicked} />
<ButtonB />
</div>
)
}
function ButtonA(props){
const renderCount = useRef(0);
console.log('<ButtonA /> is rendered', ++renderCount.current);
return (<button onClick={props.onClick} className={`${props.isClicked ? 'true':'false'}`} >Button A</button>);
}
function ButtonB(){
const renderCount = useRef(0);
console.log('<ButtonB /> is rendered', ++renderCount.current);
return (<button>Button B </button>);
}
ReactDOM.render(
<List />, document.getElementById('root')
)
button.true{
background-color: red;
}
button.false{
background-color: blue;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
It's a sample code.
When I clicked <ButtonA />, and I expected re-rendering <List /> and <Button A/>, but <ButtonB /> was also re-rendered.
I wanna block re-rendering <ButtonB /> when I click <ButtonA />
How can I achieve it?
You can make use of React.memo to have the same functionality as shouldComponentUpdate for functional component
const {useRef, useState} = React;
function List(){
const renderCount = useRef(0);
console.log('<List /> is rendered', ++renderCount.current);
const [isClicked, setIsClicked] = useState(false);
const toggle = () => setIsClicked(!isClicked)
return (
<div>
<ButtonA onClick={toggle} isClicked={isClicked} />
<ButtonB />
</div>
)
}
function ButtonA(props){
const renderCount = useRef(0);
console.log('<ButtonA /> is rendered', ++renderCount.current);
return (<button onClick={props.onClick} className={`${props.isClicked ? 'true':'false'}`} >Button A</button>);
}
const ButtonB = React.memo(() => {
const renderCount = useRef(0);
console.log('<ButtonB /> is rendered', ++renderCount.current);
return (<button>Button B </button>);
})
ReactDOM.render(
<List />, document.getElementById('root')
)
button.true{
background-color: red;
}
button.false{
background-color: blue;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Optimizing a functional component so that React can treat it as a pure component shouldn’t necessarily require that the component be converted to a class component.
If you are already familiar with the recompose package then you know that it provides a wide collection of higher-order components that makes it very useful when dealing with functional components.
The recompose package exports a {pure} higher-order component that tries to optimize a React component by preventing updates on the component unless a prop has changed, using shallowEqual() to test for changes.
Using the pure higher-order component, our functional component can be wrapped as follows:
import React from 'react';
import { pure } from 'recompose';
function ButtonB() {
const renderCount = useRef(0);
console.log('<ButtonB /> is rendered', ++renderCount.current);
return (<button>Button B </button>);
}
// Wrap component using the `pure` HOC from recompose
export default pure(ButtonB);
By default all children of the parent is re-rendered if the parent's state changes. No matters if this change has a direct effect to the child or not.
However you can explicitly disable the re-render of a specific component using the shouldComponentUpdate lifecycle method.
class Button extends React.Component {
shouldComponentUpdate(){
return !this.props.shouldNotUpdate;
}
render(){
const { id, onClick } = this.props;
console.log(`button ${this.props.id} rendered`)
return <button onClick={onClick}>{`Button ${id}`}</button>
}
}
class App extends React.Component {
state = { clicked: 0 }
handleClick = () => this.setState(({clicked}) => ({clicked: clicked + 1}))
render(){
return (
<div>
{this.state.clicked}<br />
<Button id="1" onClick={this.handleClick} />
<Button id="2" shouldNotUpdate />
</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"></div>
Related
just a curious question, if i have something like this:
const Parent= () => {
const info = `hey show this ${state}` //how can i get this state from child?
return <div>
<Child />
<iframe
srcDoc={info}
width="100%"
height="100%"
/>
</div>
}
export default Parent
const Child= () => {
const [state, setstate] = useState("");
const onclick =()=>{setstate('state from child')}
return <div>
<button onClick={onclick}>click!</button>
<p>I am a {state}</p>
</div>
}
export default Child
how can i get this state from child?
Yes, by storing the state in the parent and passing the setState function to the child:
<div id="root"></div><script src="https://unpkg.com/react#17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom#17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/#babel/standalone#7.16.6/babel.min.js"></script>
<script type="text/babel" data-type="module" data-presets="env,react">
const {useState} = React;
function Child (props) {
return <button
onClick={() => props.setValue(new Date().toLocaleString())}
>Update value</button>;
}
function Parent () {
const [dateStr, setDateStr] = useState(new Date().toLocaleString());
return (
<div>
<h2>Date: {dateStr}</h2>
<Child setValue={setDateStr} />
</div>
);
}
function Example () {
return <Parent />;
}
ReactDOM.render(<Example />, document.getElementById('root'));
</script>
I'm want to rewrite my high-order-component with useHooks. it is possible reuse stateful logic like hoc?
I have worked with hoc for a while, I think it is esay to solution some problem.
I tried to implement same features like hoc use useHooks, sorry... I failed
// HOC
const Hoc = WrapperComponent => (
class extends React.Component {
state = {
toggle: false
}
handleClick = () => {
this.setState({ toggle: !this.state.toggle })
}
render() {
const { toggle } = this.state
return (
<>
<button onClick={handleClick}>click</button>
{toggle && <WrapperComponent />}
</>
)
}
}
)
// Component A
function CompA () {
return 'class comp a'
}
// reuse logic with hoc
export default Hoc(CompA)
// this is my code.
// but i think it's hoc style. not really hooks idea
function useHooks(WrapperComponent) {
const [toggle, setToggle] = useState(false)
return () => (
<>
<button onClick={() => setToggle(!toggle)}>click</button>
{toggle && <WrapperComponent />}
</>
)
}
//
export default useHooks(ClassCompA)
Hooks is designed to share any necessary logic between the components.
Presentational elements like JSX are not included in this logic. They are best left at the components which can be composed to any level necessary.
For your example using the HOC, there would need to be a component for the presentation and hooks for sharing the logic.
const { useState, Fragment } = React;
function useToggle() {
const [ show, setShow ] = useState(false);
const toggle = () => {
setShow(show => !show);
}
return {
show,
toggle,
}
}
function Toggler({ children }) {
const { show, toggle } = useToggle();
return (
<Fragment>
{show && children }
{<button onClick={toggle}>Toggle View</button>}
</Fragment>
);
}
function App() {
return (
<Toggler>
<h1>This content can be toggled</h1>
</Toggler>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
I known how to pass data from a component to other but what I want to do is to have two independent component where one of them pass data to the other.
For example, <Component 1> pass data to <Component 2>. I don't want to pass data to <Component 2> inside the code of <Component 1>. What I want to know if its possible to pass data and how from <Component 1> to <Component 2>. Because, I want to have an independent component which makes its own tasks and at the end of these tasks, pass the data to other component which is not included in her own code.
This would be an example what I would like to do:
class Test extends Component{
constructor(){
super()
}
render(){
return(
<div>
<h1>Test</h1>
<Component 1 />
<Component 2 />
</div>
)
}
}
Therefore, is there any way to pass data between independent components in React.js?.
const { useState, createContext, useContext } = React;
const Context = React.createContext();
const MyComponent = () => {
const { name, updateName } = useContext(Context);
return (<span onClick={() => updateName('Jane')}>{name}</span>);
};
const App = () => {
const [name, updateName] = useState('John');
return (
<Context.Provider value={{ name, updateName }}>
<MyComponent />
<br/>
<MyComponent />
</Context.Provider>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="root" />
to exercise the snippet...
click on John to update name to Jane
You should be using state in the parent component that holds both the components and use some way of updating the parent state by the child component and consume it, in its basic way. Advanced way is to use Redux, but I don't think your current example needs it.
Let me show you a small example.
const Component1 = props => (
<div>
<h1>Component 1</h1>
<p>Please change the value here:</p>
<input
type="text"
onChange={e => props.changeState(e.target.value)}
value={props.value}
/>
</div>
);
const Component2 = props => (
<div>
<h1>Component 2</h1>
<p>Let me show the common value here:</p>
<pre>{props.value}</pre>
</div>
);
class App extends React.Component {
state = {
commonValue: "Hello"
};
changeState = val => {
this.setState({
commonValue: val
});
};
render() {
return (
<div className="App">
<Component1
value={this.state.commonValue}
changeState={this.changeState}
/>
<Component2 value={this.state.commonValue} />
</div>
);
}
}
This way, you will be able to change the values from two different components.
Working Snippet
const Component1 = props => (
<div>
<h1>Component 1</h1>
<p>Please change the value here:</p>
<input
type="text"
onChange={e => props.changeState(e.target.value)}
value={props.value}
/>
</div>
);
const Component2 = props => (
<div>
<h1>Component 2</h1>
<p>Let me show the common value here:</p>
<pre>{props.value}</pre>
</div>
);
class App extends React.Component {
state = {
commonValue: "Hello"
};
changeState = val => {
this.setState({
commonValue: val
});
};
render() {
return (
<div className="App">
<Component1
value={this.state.commonValue}
changeState={this.changeState}
/>
<Component2 value={this.state.commonValue} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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"></div>
Working Demo: https://codesandbox.io/s/priceless-sea-e7d99
If you need to have dependent data for independent components - you need to lift your state up to a common parent component.
For your particular example, the Test component might contain data needed to be shared between Component1 and Component2 as well as handlers for its changing.
You can read more about this in official documentation about Lifting State Up.
This is my components logic:
component_1
|
'------component_2
I have an input in component_2, and I want to put .focus () on it, but the function that will do this is in component_1, how can I do it?
And I think it will do the ref, if I'm wrong please correct me.
Since React 16.3, you can use React.createRef() in Component1 and pass it to the input via Component2 using ref forwarding:
const Component2 = React.forwardRef((props, ref) => (
<input ref={ref} />
));
class Component1 extends React.Component {
ref = React.createRef();
componentDidMount() {
setTimeout(() => this.ref.current.focus(), 1000);
}
render() {
return <Component2 ref={this.ref} />;
}
}
ReactDOM.render(
<Component1 />,
document.getElementById('demo')
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="demo"></div>
I have multiple React components that will receive the same props...
...
render () {
const { someProps } = this.props
return (
<div className="someDiv">
<Component1 someProps={someProps}/>
<Component2 someProps={someProps}/>
</div>
)
}
...
The above code works fine but is there a more dynamic way of doing this? Mabye do a .map() over an array of Component names?
Array of components should work just fine.
const Component1 = (props) => <div>Component 1</div>
const Component2 = (props) => <div>Component 2</div>
const Component3 = (props) => <div>Component 3</div>
const components = [Component1, Component2, Component3]
class App extends React.Component {
render() {
const { someProps } = this.props
return (
<div>
<h3>Root component</h3>
{components.map((Component, index) =>
<Component key={index} someProps={someProps} />
)}
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>