Modularize React Code: Same format, different function - reactjs

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.

Related

Making a function component from a class component. What is props here?

I was trying to implement a drag and drop functionality to my ant design tabs component. The example they mentioned in the documentation is class based. I was trying to make it into function component but I am not sure what props are in this case.
Ant design demo
Official documentation
For example, I got confused here, this class component itself is outside another class component. How would react extract these connectDragSource, connectDropTarget, children when it has noting that is being passed from the props? And how would I extract these when I am in a function component?
class TabNode extends React.Component {
render() {
const { connectDragSource, connectDropTarget, children } = this.props;
return connectDragSource(connectDropTarget(children));
}
}
and there are some other aspects in the provided demo that are confusing to me. It would be great help if you could breakdown and explain what is happening so that I can turn this into a react functional component.
In functional component you can access props as one of your component's argument, and also instead of returning your JSX by render method, whatever you returns by your functional component, considers as your JSX output, like this:
function MyComp(props){
// do whatever you want by props (actually body of your function is equivalent to render method in class component)
return (<div>...</div>);
}
Here I implemented your tab example by function component.

Updating outside React component

I have a component for displaying news somewhere in the page. You can rate news (give stars to it).
I have another component in another place where some news are displayed. In that component you can rate the news as well. I want to update News component (rerender it) after a vote was given in <SomeComponentWhereNewsAreDisplayed />. Is there a way to do it?
Some pseudocode:
class SomeComponentWhereNewsAreDisplayed extends React.Component
{
voteAndUpdateNewsComponent() {
updateNewsComponent()
}
render() {
return <div>
...
<some functionality that allows to give a star to news onClick={this.voteAndUpdateNewsComponent}>
...
</div>
}
}
class News extends React.Component
{
componentDidMount() {
//..ajax request to get ratings, or taking it from localStorage, etc..
}
render() {
return <div>
{this.state.ratings.map(rating => { return <span>{rating.stars}</span>})
</div>
}
};
Hello you can use state management like Redux or Context for solve this problem.
Generally speaking, if two React components don't belong in the same component hierarchy, they cannot exchange data. There are a number of hacks to go around these, but ideally you want to put them in the same hierarchy and exchange props and callbacks.
If you don't want to do that, you still have Redux at your disposal to pull the state management out of the hierarchy: https://react-redux.js.org/api/connect
You dont need to use a state container for this. Pass down a function from SomeComponentWhereNewsAreDisplayed to News that updates the state of SomeComponentWhereNewsAreDisplayed and is attached to the click handler of the star rating in News. This causes your parent (SomeComponentWhereNewsAreDisplayed) and its children to rerender.

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.

Updating state in more than one component at a time

I have a listview component which consists of a number of child listitem components.
Each child listitem have a showSubMenu boolean state, which display a few extra buttons next to the list item.
This state should update in response to a user event, say, a click on the component DOM node.
childcomponent:
_handleClick() {
... mutate state
this.props.onClick() // call the onClick handler provided by the parent to update the state in parent
}
However, it feels somewhat wrong to update state like, as it mutates state in different places.
The other way i figured i could accomplish it was to call the this.props.onClick directly, and move the child state into the parent as a prop instead, and then do change the state there, and trickle it down as props.
Which, if any, of these approaches is idiomatic or preferable?
First of all, I think that the question's title doesn't describe very well what's your doubt. Is more an issue about where the state should go.
The theory of React says that you should put your state in the higher component that you can find for being the single source of truth for a set of components.
For each piece of state in your application:
Identify every component that renders something based on that state.
Find a common owner component (a single component above all the
components that need the state in the hierarchy).
Either the common
owner or another component higher up in the hierarchy should own the
state.
If you can't find a component where it makes sense to own the
state, create a new component simply for holding the state and add it
somewhere in the hierarchy above the common owner component.
However, a Software Engineer at Facebook said:
We started with large top level components which pull all the data
needed for their children, and pass it down through props. This leads
to a lot of cruft and irrelevant code in the intermediate components.
What we settled on, for the most part, is components declaring and
fetching the data they need themselves...
Sure, is talking about data fetched from stores but what im traying to say is that in some cases the theory is not the best option.
In this case i would say that the showSubMenu state only have sense for the list item to show a couple of buttons so its a good option put that state in the child component. I say is a good option because is a simple solution for a simple problem, the other option that you propose means having something like this:
var GroceryList = React.createClass({
handleClick: function(i) {
console.log('You clicked: ' + this.props.items[i]);
},
render: function() {
return (
<div>
{this.props.items.map(function(item, i) {
return (
<div onClick={this.handleClick.bind(this, i)} key={i}>{item} </div>
);
}, this)}
</div>
);
}
});
If, in a future, the list view has to get acknowledge of that state to show something for example, the state should be in the parent component.
However, i think it's a thin line and you can do wathever makes sense in your specific case, I have a very similar case in my app and it's a simple case so i put the state in the child. Tomorrow maybe i must change it and put the state in his parent.
With many components depending on same state and its mutation you will encounter two issues.
They are placed in component tree so far away that your state will have to be stored in a parent component very high up in the render tree.
Placing the state very high far away from children components you will have to pass them down through many components that should not be aware of this state.
THERE ARE TWO SOLUTIONS FOR THIS ISSUE!
Use React.createContext and user context provider to pass the data to child elements.
Use redux, and react-redux libraries to save your state in store and connect it to different components in your app. For your information react-redux library uses React.createContext methods under the hood.
EXAMPLES:
Create Context
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
REDUX AND REACT-REDUX
import { connect } from 'react-redux'
const App = props => {
return <div>{props.user}</div>
}
const mapStateToProps = state => {
return state
}
export default connect(mapStateToProps)(App)
For more information about redux and react-redux check out this link:
https://redux.js.org/recipes/writing-tests#connected-components

Resources