Struggling with this.props in nested components - reactjs

Apologies if this is a basic question but I am new to react/gatsby and i am struggling to find an answer to my question as i am not sure the exact terminology.
I am currently building a site using atomic design principles. i want to update the copy for atom components such as buttons/forms when they are used around the site - however i am struggling to pass data using the methods i know of.
Code set up
Atom/Button components the text is coded as such
<button>{this.props.copy}</button>
Layout component such as a hero banner The button is imported in the layout using
<section>This is a hero banner <button copy="copy goes here" /></section>
Page component I want to use the layout/hero component across various pages, I've imported the layout component and overwrite the button text already defined in the layout component however using
<layout copy="overwrite the copy"> obviously will not work
Is there a way to either pull a component into another component as it is called in such as <hero <button copy="new copy"/> /> and overwrite the prop. OR a better way to define props in the atom components that they can be nested. so the structure looks like this (the third level components are always in layouts and rarely pulled into the page by themselves.)
Page 1
Page 2
├── Layout (Hero)
├─────── Atom (button)
├─────── Atom (Input)
└─────── Atom (Select)
any help would be greatly appreciated.

You have a couple options here:
Prop Drilling
Render Props (React docs).
I am going to say avoid Prop Drilling as much as possible. It becomes cumbersome on large component hierarchies. Try a more dynamic approach with the render props that allows you swap out implementations with out causing issues.
Prop Drilling:
This would involve passing props down the component hierarchy. For your use case, it would look like this
class Layout extends Component {
render() {
return (
<section>
This is a hero banner <AtomButton copy={this.props.copy} />
</section>
)
}
}
class AtomButton extends Component {
render() {
return (
<button>this.props.copy</button>
)
}
}
Render Props:
What I am showing here is not actually a render prop. This is just passing a component down as a prop and then rednering the component. A true render props is defined in the React docs I linked.
class Layout extends Component {
render() {
return (
<section> This is a hero banner {this.props.button} /><section>
)
}
}
//Wherever your are loading your Layout Component
class Page extends Component {
render() {
return (
<Layout buttonRender={<AtomButton copy="overwrite copy" />} />
)
}
}

Related

Can I get my React component to render conditionally with renderToStaticMarkup?

I have a list of components that I'm preparing for automated visual regression testing (VRT) and have a system set up to do that rendering them individually with ReactDOM.renderToStaticMarkup for the tests to reference.
On the visual side, theses components are sometimes wrapped in a WrapperComponent with extra styles to display them differently when viewed on screen for human eyes.
Is there a way to make the WrapperComponent aware of its renderer (so to speak), so that I can conditionally omit the WrapperComponent from the markup that's sent to VRT?
Essentially I'd to do something like:
ReactDOM.renderToStaticMarkup(componentPossiblyWithWrapperComponentInside)
In the WrapperComponent:
class WrapperComponent extends React.Component {
render() {
return isBeingRenderedForVRT ?
this.props.children :
(
<div className='wrapper-component-for-human-screens'>
{this.props.children}
</div>
)
}
}

Context and childContextTypes

I've seen some code examples on github that uses some different kind of props.
I saw childContextTypes and context.
But the implementation is different, though the usage looks similar.
some code looks like this:
propTypes: {
a: React.PropTypes.string
},
childContextTypes: {
a: React.PropTypes.string
},
getChildContext() {
return {
a: this.props.a
}
}
contextTypes: {
a: React.PropTypes.string,
b: React.PropTypes.string
},
render() {
return (
<div>
Three
({this.context.a}, {this.context.b})
</div>
);
}
I've read about it on the net and in stack-overflow but could not understand what is it exactly and where or why to use it?
Why there are more examples of props then contextTypes?
UPDATE - March 29, 2018
Since react v16.3.0, a new context API was released and is considered "safe" to use. though you should still think twice before using it:
Context is primarily used when some data needs to be accessible by many components at different nesting levels. Apply it sparingly because it makes component reuse more difficult.
If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.
Before you read further let me quote something from React context DOCS
If you want your application to be stable, don't use context. It is an
experimental API and it is likely to break in future releases of
React.
Now it's !safe to read further.
You can use the context API in order to access data that exists in the parents scope, without passing it down to the child component.
This is useful when you don't want to pass down the data manually on each level.
For example, given this scenario:
<Root/> component that renders a child <List/> component.
<List/> component renders a collection of Item components
<Item/> renders a <Button/> (among other components).
Now lets say that the Button component needs certain data from the Root component, like isEnabled which will render a disabled or enabled Button.
This kind of data is set on the top level component the <Root/>, but in order to pass it down to the Button component we will need to pass it down on each level:
<Root/> -> <List isEnabled /> -> <Item isEnabled /> -> <Button isEnabled/>
Well, this is kinda tedious and irrelevant for all other components down the tree.
With the context API you can "skip" this tree flow of passing this data as prop and expose this data in the context object at the top level Root component, then access it directly within the Button component via the context object. You can think of it as if the context is in a shared scope of the parent and child components.
You can also do Parent-Child Coupling, And as the docs mentions, some libraries like react-router use this API in order to pass the data upwards from child components to the container.
Context are really different in use and definition than Props.
Where to use it? Well, if you can survive without it, it means that you don't really need it.
Context values are passed from the parent-that-declared-it, and accessible to all of their children, all of them in the entire app tree, if they "ask" for.
A good example is how <Provider /> in Redux works, so you declare a lot of children, and the connected components (components that you passed throughout connect() internally ask for this context, so no matter where is declared, if this component is inside Provider, it has access to Provider context. And you doesn't have to manually pass all the store through components.
class MyProvider extends React.Component {
getChildContext() {
return {
color: "#6257af"
}
}
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
MyProvider.childContextTypes = {
color: window.PropTypes.string
}
class Main extends React.Component {
render() {
return (
<Text />
)
}
}
class Text extends React.Component {
render() {
return (
<p style={{ color: this.context.color }}>Hi! Context color {this.context.color}</p>
)
}
}
Text.contextTypes = {
color: window.PropTypes.string
}
ReactDOM.render(
<MyProvider>
<Main />
</MyProvider>, 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>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<div id="root"></div>
Hope it helps :)

How does one React component call a method in another React component?

My page contains two completely separate React components (different files, different classes, no parent-child relationship).
How can one component call an instance method in another component? The problem seems to be obtaining the instance of the target component.
EDIT: Both components share the same parent (i.e. they are rendered in the same render() method) but I still don't know how to pass the reference of the target component to the calling component.
The short answer is: they don't.
It's not clear what you're trying to accomplish, so I can't speak to the specifics of your case, but the way React components "communicate" with one another is via state and props. For example, consider a Page component that has two child components, CompA and CompB, rendered something like this:
<Page>
<CompA />
<CompB />
</Page>
If CompA needs to pass something to CompB, this is done through state on the Page component, with that state exposed as props on CompA and CompB, something like this:
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
sharedValue: 42,
};
}
onChangeSharedValue(newValue) {
this.setState({ sharedValue: newValue });
}
render() {
return (
<div>
<CompA
sharedValue={this.state.sharedValue}
onChange={this.onChangeSharedValue}
/>
<CompB
sharedValue={this.state.sharedValue}
onChange={this.onChangeSharedValue}
/>
</div>
);
}
}
If CompA needs to change the shared value, it calls the onChange handler, which will change the state on the Page component. That value will then be propagated down to the CompB component.
There is no direct communication between components like you're describing; it is all done via state and props.
"Props down, Events up."
If you provide us a specific example of what you're looking for, I can update this post with a more specific response.
But in general, there are a couple of strategies that you can take. Some of them are presented here.
The preferred approach is to simply move your calling method to the parent component. It's a common strategy in React.
If you're not able to, then the next step would be to write an event handler for the parent, and then pass this event down to the first child component.
Use this event to pass information up to the parent, so that when it gets triggered, data can be passed as props down to the second component.
I only recently started doing React development and I found a solution for this problem that suits me. Admittedly, I haven't seen it referenced anywhere and when I showed it to a colleague who's been doing React for years, he kinda furrowed his brow and felt that it wasn't "right", but he couldn't really articulate to me why it's "wrong". I'm sure I'll be shouted down for it here, but I thought I'd share anyway:
File #1: objects.js
let objects= {};
export default objects;
File #2: firstComponent.js
import React from 'react';
import objects from 'objects';
class FirstComponent extends React.Component {
constructor(props) {
super(props);
objects['FirstComponent'] = this; // store a reference to this component in 'objects'
}
doSomethingInFirstComponent() {
console.log('did something in first component');
}
render() {
return (<div></div>);
}
}
export default FirstComponent;
File #3: secondComponent.js
import React from 'react';
import objects from 'objects';
class SecondComponent extends React.Component {
render() {
objects.FirstComponent.doSomethingInFirstComponent(); // call the method on the component referred to in 'objects'
return (<div></div>);
}
}
export default SecondComponent ;
When SecondComponent renders, it will trigger the console.log() in FirstComponent.doSomethingInFirstComponent(). This assumes, of course, that FirstComponent is actually mounted.
The "React Guys" that I know seem to think this approach is somehow evil. It uses a simple JavaScript object outside the normal React scope to maintain a reference to any existing objects that I choose to store there. Other than them telling me that "this isn't the way you do things in React", I haven't yet found a good explanation for how this will break or otherwise screw-up my app. I use it as a low-grade replacement for massive-overkill state-management tools like Redux. I also use it to avoid having to pass properties down through dozens of layers of React components just so something at the last level can trigger something waaaaay up in the first level.
That's not to say this approach doesn't have it's problems:
It creates an obvious dependency between the generic objects object, any component that is designed to store a reference to itself inside objects, and any component that wishes to utilizes those references. Then again, using any kind of global state-management solution creates a similar dependency.
It's probably a bad solution if you have any doubt that FirstComponent will be mounted before you try to call it from within SecondComponent.
I've found that just having the reference to a React component won't allow you to do all the things that React components can do natively. For example, it won't work to call objects.FirstComponent.setState(). You can call a method in FirstComponent, which in turn can invoke its own setState(), but you can't invoke FirstComponent's setState() directly from within SecondComponent. Quite frankly, I think this is a good thing.
You can, however, directly access the state values from the components referenced in objects.
This should only be done with "global" components (components that functionally serve as singletons). If, for example, you had a simple UI component called BasicSpan that did little more than render a basic span tag, and you proceeded to use that component over and over again throughout your React app, I'm sure it would quickly become an unmanageable nightmare to try to place references to these simple components in the objects object and then try to intelligently manage calls to those components' internal methods.
you can send an event as props and call it from other component.
Say you have a class
Class A{
handleChange(evt)
{
this.setState({
name:evt.target.value
})
}
render{
return(
<div>
<ComponentB name={this.state.name}{ onChange={this.handleChange}/>
</div>
);
}
}
Child Component
Class B{
handleChange()
{
//logic
}
render{
return(
<div>
<input type="text" onChange={this.props.onChange}/>
{this.props.name}
</div>
);
}
Here in Component B when you change the input it will call the method
of class A and update state of A.
Now getting the updated state as props in component B will give you
the changed text that you just entered

How can I find all nested Components using React/Redux?

I am looking to validate a form with Redux. I am trying to use make a form component which will iterate through children and find various input components (not to be confused with a native <input>.
I know there are a lot of open source solutions, but I'd like to understand some mechanics before jumping into picking any. I have a Form component setup to test like this:
import React from 'react';
export default class Component extends React.Component {
componentDidMount() {
this._iterate(this.props.children);
}
render(){
return (
<form {...this.props}>{this.props.children}</form>
);
}
_iterate(children) {
React.Children.forEach(children, child => {
console.log(child);
if (child.props.children) {
console.log('get children');
this._iterate(child.props.children);
}
});
}
};
I then have another Component with a render like this:
render() {
return (
<div>
<Form>
<ComponentA />
<ComponentB />
</Form>
</div>
);
}
Now ComponentA or ComponentB might have a component that nests more components down the line. Within those components would be a React component I have made for Text, Select, etc.
The code above would just console.log the components, and any children of them, that are in this specific render. It does not jump down into ComponentA children.
Is there a solution to that?
This isn't a problem you really want to solve.
The power in react is largely around the design pattern it encourages, and what you're doing is breaking that pattern; Component's should only talk to their immediate children and respond to their immediate parents. If you need to go deeper than that, then the component in the middle needs to be responsible for passing that data.
Rather than trying to dig into the innards of ComponentA and ComponentB, those component's themselves should have the accessibility props that you need. I.e., <ComponentA onChange={whatever} errorMessage={whatever}/> etc. and then hooking those props to their children should occur within ComponentA.

Modularize React Code: Same format, different function

I made a simple ToDo List in React.
I have a component for Adding a new ToDo item (eg. name, title, date, place, description), and another component for Editing a ToDo item.
The 2 components however, are exactly the same, except that the Edit component is filled with content.
Is there I way I can simplify this, eg. nest a "general form" component for both the Edit and Add Component? And should I be looking into higher order components?
You can make a renderedTodo component and pass property isEditing, for example. And inside render function pick proper component to render
class TodoItem extends React.Component {
render() {
const renderedTodo = this.props.isEditing ? (<EditingTodo>) : (<AddingTodo>);
return (
<div>
<div>[Common structure]</div>
{ renderedTodo }
</div>
);
}
}
TodoItem also manages all common logic, EditingTodo and AddingTodo only logic related to them. They should be pure functions without any state and do everything using received props from TodoItem.

Resources