Automatically map the same props to multiple React components - reactjs

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>

Related

How do I pass props from Child to Parent in React for incremental onClick?

export default class App extends React.Component {
constructor() {
super();
this.state = {
todos: 5
};
}
handleClick = () => {
this.setState({ todos: this.state.todos + 1 });
};
render() {
return (
<div className="App">
<h1>ToDo List</h1>
<p>Just keep giving me things to do</p>
<p>I still have {this.state.todos} things to do</p>
<AddTodo todos={this.state.todos} handleClick={this.handleClick} />
</div>
);
}
}
I am trying to update <p>I still have {this.state.todos} things to do</p> in the Parent to increase by 1 for every button click in the Child Component. What am I missing? I am not getting any errors but it is not functional.
import React from "react";
export default function AddTodo(handleClick) {
return (
<div className="AddTodo">
<button onClick={() => handleClick}>Add Another</button>
</div>
);
}
Props is the first value passed to a functional component, it's an object and you would need to destructure handleClick from it.
export default function AddTodo({ handleClick }) {
return (
<div className="AddTodo">
<button onClick={handleClick}>Add Another</button>
</div>
);
}
Also change your handle click function to this
handleClick = () => {
this.setState(({ todos }) => ({ todos: todos + 1 }));
};
a working example
const AddTodo = ({ onClick }) => (
<div className="AddTodo">
<button onClick={onClick}>Add Another</button>
</div>
);
const App = () => {
const [todos, setTodos] = React.useState(5);
const onClick = () => {
setTodos((oldTodos) => oldTodos + 1);
};
return (
<div className="App">
<h1>ToDo List</h1>
<p>Just keep giving me things to do</p>
<p>I still have {todos} things to do</p>
<AddTodo todos={todos} onClick={onClick} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://unpkg.com/react#17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>

react component render method being called twice for no reason

import './App.css';
import SolarSystem from './components/solarSystem/solarSystem';
class App extends React.Component {
componentDidMount(){
console.log("mounting");
}
componentDidUpdate(){
console.log("updating");
}
//const [SSVisibility, setSSVisibility] = useState(true);
render(){
console.log("rendering app");
return (
<div className="App">ssssssssssssssssssssssssssssssss
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
export default App;
With this simple code, my render method is being called twice. And i cant understand why
It is because of strict mode, code below doesn't demonstrate it because SO will build it with production set true (I think).
class Strict extends React.Component {
componentDidMount() {
console.log('mounting strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
class NonStrict extends React.Component {
componentDidMount() {
console.log('mounting non strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering Non strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
const App = () => {
return (
<div>
<React.StrictMode>
<Strict />
</React.StrictMode>
<NonStrict />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>

ReactJS Call Function of another Component react-router

I have implemented an app which uses react-router to handle the routes in my web-app. I want to trigger the function logintoggle which is on the Header.js component from a function from the Hompage.js component. The App.js has all the routes in one file.
Can anyone explain to me how this can be achieved with small code snippet?
App.js
render() {
const { location } = this.props;
return (
<IntlProvider
locale="a"
messages="s"
>
<Fragment>
<div>
<Headers />
<Switch>
<Route exact path="/women" component={HomePage} />
</Switch>
</div>
</Fragment>
</IntlProvider>
);
}
}
export default App;
Header
class Header extends React.Component {
constructor(props) {
super(props);
}
logintoggle(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
}
}
Homepage.js
class CheckOut extends Component {
constructor(props) {
super(props);
}
}
When you need to have a shared state among the components React.Context API is what you need. It allows you to create a separate context provider, which will provide the state and the methods to manipulate this state to all the components you need. In the example below I have a LoginContextProvider with activeTab state variable. I provide activeTab and setActiveTab to all the components inside LoginContextProvider's children. Header changes activeTab to 1, Homepage changes to 2 and LoginContextDebug represents the actual activeTab value.
const LoginContext = React.createContext(null);
const LoginContextProvider = ({ children }) => {
const [activeTab, setActiveTab] = React.useState(0);
return (
<LoginContext.Provider value={{ setActiveTab, activeTab }}>
{children}
</LoginContext.Provider>
);
};
const Header = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am header</h1>
<button onClick={() => setActiveTab(1)}>Set activeTab to 1</button>
</div>
);
};
const Homepage = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am homepage</h1>
<button onClick={() => setActiveTab(2)}>Set activeTab to 2</button>
</div>
);
};
const LoginContextDebug = () => {
const { activeTab } = React.useContext(LoginContext);
return (
<pre style={{ padding: 10, background: "lightgray" }}>
activeTab={activeTab}
</pre>
);
};
const App = () => (
<LoginContextProvider value={null}>
<Header />
<Homepage />
<LoginContextDebug />
</LoginContextProvider>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

React: How can I pass data between independent components

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.

re-render only one child with react-hooks

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>

Resources