React: Creating Another instance of the same control - reactjs

I have created an app which is working pretty well. My app.jsx looks like
const App = () => (
<div>
<DimensionPicker dimensionName="genre"/>
<TableControl />
</div>
)
export default App;
Well. this is good. but now I want another instance of dimension picker on the same report like
const App = () => (
<div>
<DimensionPicker dimensionName="genre"/>
<DimensionPicker dimensionName="year"/>
<TableControl />
</div>
)
export default App;
Well it turns out that this is pretty hard to do because the second instance will overwrite the state which I have created in my store.
How can this situation be addressed?

So I think the problem here is that both Instances have the same business logic, as everything is handled internally. So both override the same state in your store, cause both Instances trigger the same callbacks.
What I do, when I want one Presentational Component to have different functionality is simply wrap them and inject the required callbacks as props.
I would do it like this (pseudo code):
GenrePicker extends Component {
handleBehaviour() {
// define GenrePicker specific logic here
dispatch(STATE_CHANGE_GENREPICKER)
}
render() {
return (<DimensionPicker onPickHandler={this.handleBehaviour} dimensionName="genre"/>)
}
}
YearPicker extends Component {
handleBehaviour() {
// define YearPicker specific logic here
dispatch(STATE_CHANGE_YEARPICKER)
}
render() {
return (<DimensionPicker onPickHandler={this.handleBehaviour} dimensionName="year"/>)
}
}
And in your App
const App = () => (
<div>
<GenrePicker />
<YearPicker />
<TableControl />
</div>
)
export default App;
I always use to program my presentational components only against props. In your case I would treat the DimensionPicker as a dumb presentational Component and use concrete Components to inject the required logic.
Regarding the problem with the state override. Shouldn't both Components have their own state property? state = { selectedYear: '', selectedGenre: '' } and therefore dispatch an action in their's handleBehaviour() method that only propagates it's own state change?

Related

How to change state of component from anywhere without Redux?

Is this bad practices or not ?
export state change function from component
import it from other file.
call the function to change state?
In this way we can change some component state from anywhere.
For example...
We want to change the Model.js state from anywhere.
Modal.js
import React from 'react';
export let toggleModal;
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
};
toggleModal = this.toggleModal;
}
toggleModal = () => {
this.setState({ open: !this.state.open });
};
render() {
const { open } = this.state;
return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
}
}
App.js(Some Top Level component)
import React from 'react';
import Modal from './Modal';
export default () => (
<>
...
<Modal />
...
</>
);
Somewhere.js
import React from 'react';
import {toggleModal} from './Modal';
export default () => (
<>
<h1>Hello!</h1>
<button onClick={() => toggleModal()}>open Modal!</button>
</>
);
  
But there is no reference in React Official docs, so is this bad practices ?
What React Docs recommends...
Just passing function props to change parent state from parent to children
Use context
Redux or Mobx
But, these are too complex for me.
Example code here
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview
Everything seems pretty much overwhelming and difficult at the beginning. But as we get out hands on them, it's give us more confidence to dig into.
I would recommend to use redux that's how we tackled props drilling problem. You can dispatch a action and connect reducer to corresponding component which upon updating state will re render. This is what I recommend to most of the people to learn the tale of redux with a real life example:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
Apart from this you can take Dan Abramov, author of the library, free redux course on egghead.io:
Getting Started with Redux
The problem you run into, almost immediately like your code example does is this:
It will not work: your toggleModal() method expects a this to refer to an actual component instance. When your onClick() handler fires you invoke toggleModal() as a plain function. The this context will be wrong, and so at best (in your example) you will get an error because you try to invoke something undefined, at worst (in general) you end up invoking the wrong method.
When you think about it, for any non-trivial React component you will have a hard time obtaining a reference to the actual instance that is currently being used: you have to make sure that you are not forgetting to invoke the method on the right component instance and also you have to consider that instances may be created/destroyed 'at will' for whatever reason. For example: what if your component is rendered indirectly as part of some other component's render() method? Multiple layers of indirection like that make it even harder.
Now, you could fix all that by abusing ref with abandon but you will find that now you have to keep track of which ref refers to what particular instance, if you happen to have multiple of the components to consider in one render tree...
Whenever you think one component needs to handle the state of its siblings, the solution is usually to lift the state one level up.
export default class Modal extends React.Component {
render() {
const { isOpen } = this.props;
return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
}
}
export default class Home {
this.state = {
isOpen: false,
};
toggleModal = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
const { isOpen } = this.state;
return (
<>
<h1>Hello {name}!</h1>
<button onClick={() => this.toggleModal()}>open Modal!</button>
<Modal isOpen={isOpen}/>
<p>Start editing and see your changes reflected here immediately!</p>
</>
)
}
}
This way the Home handle the state and your problem is solved.
This can get annoying if the state needs to be "drilled down" to children, that's a problem than redux or react-context can solve.
Here <Modal /> is the child component. So to call a function in a child component you can simply use Ref.
You can refer this page to get more info about Ref.
You can assign a class variable as a ref to this child and use this class variable as an object to call its function.
I found if in special case, my way is okay.
Special case means something like customAlert component.
It is okay only one instance of customAlert component mounted at a time in App.
To achieve this...
1.Use ref to access and change DOM
2.attach state changing function or component to window and call window.function
3.my case: export state changing function and import it from other file.
And here is how to do with react Context
https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview
I think Redux is overkill if the main thing you are interested in is to make some states-like data available and updatable throughout your App without props drilling.
For that purpose, a much simpler approach (maybe not available at the time the question was posted?) is to use react context: https://frontend.turing.edu/lessons/module-3/advanced-react-hooks.html
"context - an API given to us by React, allowing for the passing of
information to child components without the use of props
[...]
useContext - a react hook, allowing functional components to take
advantage of the context API"

Rerendering React components after redux state's locale has updated

I've implemented Redux in my React application, and so far this is working great, but I have a little question.
I have an option in my navbar to change the locale, stored in redux's state. When I change it, I expect every component to rerender to change traductions. To do this, I have to specify
locale: state.locale
in the mapStateToProps function... Which leads to a lot of code duplication.
Is there a way to implicitly pass locale into the props of every component connected with react-redux ?
Thanks in advance!
Redux implements a shouldComponentUpdate that prevents a component from updating unless it's props are changed.
In your case you could ignore this check by passing pure=false to connect:
connect(select, undefined, undefined, { pure: false })(NavBar);
For performance reasons this is a good thing and probably isn't what you want.
Instead I would suggest writing a custom connect function that will ensure locale is always added to your component props:
const localeConnect = (select, ...connectArgs) => {
return connect((state, ownProps) => {
return {
...select(state, ownProps),
locale: state.locale
};
}, ...connectArgs);
};
// Simply use `localeConnect` where you would normally use `connect`
const select = (state) => ({ someState: state.someState });
localeConnect(select)(NavBar); // props = { someState, locale }
To cut down the duplication of code I usually just pass an arrow function to the connect method when mapping state to props, looks cleaner to me. Unfortunately though, I don't think there is another way to make it implicit as your component could subscribe to multiple store "objects".
export default connect((state) => ({
local: state.locale
}))(component);
To solve this problem, you can set the Context of your parent component, and use it in your child components. This is what Redux uses to supply the store's state and dispatch function to connected React components.
In your Parent component, implement getChildContext and specify each variable's PropType.
class Parent extends React.Component {
getChildContext() {
return {
test: 'foo'
};
}
render() {
return (
<div>
<Child />
<Child />
</div>
);
}
}
Parent.childContextTypes = {
test: React.PropTypes.string
};
In your Child component, use this.context.test and specify its PropType.
class Child extends React.Component {
render() {
return (
<div>
<span>Child - Context: {this.context.test}</span>
</div>
);
}
}
Child.contextTypes = {
test: React.PropTypes.string
};
Here's a demo of it working.
I might as well mention that, while libraries like Redux use this, React's documentation states that this is an advanced and experimental feature, and may be changed/removed in future releases. I personally would not recommend this approach instead of simply passing the information you need in mapStateToProps, like you originally mentioned.

React: Nested Reusable Composition Components within a Higher Order Component

I've been trying to wrap my head around this problem for a while. I've hacked together a solution that works, until I get any nested divs, then things fall apart. Basically what I'm trying to do is create composition components that live within a higher order component and all share the same current state. I then need to export that so that any file can use those components. So here's what the JSX might look like:
<Panel countersStartAt=5>
<Counter incrementsBy=1 />
<div>
<Counter incrementsBy=2 />
</div>
<TotalCounter className="someclass" />
</Panel>
So the way I want something like this to work is that I have this wrapper Panel component that sets some initial state, say this.state.start = 5. Within Panel, a Counter component would have an onClick handler that increments state.start by incrementsBy. And TotalCounter would be a component that displayed state.start. Of course this is a contrived example, so it would be helpful not to bring up how I could make this particular component better. I'm looking to apply this to a more realistic situation.
The second thing would be how to export those components in a way that I can create the exact code above in a separate file within a stateless component. Hopefully that makes sense.
This is a snippet of what I'm doing to achieve this.
renderChildren = (children) => {
return React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.createElement(
(child.type.name ? this[child.type.name] : child.type),
child.props
);
}
return child;
});
};
render = () => {
return (
{this.renderChildren(this.props.children)}
)
};
Then outside of the Panel class I'm exporting like so:
export const Counter = () => null;
Just so it exposes Counter. The default render of null doesn't happen because I replace Counter with the this.Counter() method within Panel.
Questions asked in Comments and Other things to consider
I am not using Flux or Redux
Assume that the Panel code snippet is used in several render methods across several projects that do not implement Flux patterns or Redux
Assume that those code snippets can't be re-written
How can can Panel, Counter, and TotalCounter be exported? Is it possible to do this for Counter and TotalCounter as they are methods within the Panel class? My research led to no, and creating "dummy" components to be exported so that the current file can use them without errors.
To put in an answer here for what we talked about in the chat room
the best way to handle what you want to do without a data management framework like Redux or Flux is to pass your data as props through, like so.
class Panel extends Component {
constructor(){
super()
this.state = {count: 5}
}
incrementCount = (incrementer) => {
this.setState({count: this.state.count + incrementer});
}
render (){
return (
<div>
<Counter incrementCount={this.incrementCount} count={this.state.count} incrementsBy=2 />
</div>
);
}
}
then in your counter..
<someElement onClick={ (e) => {this.props.incrementCount(this.props.incrementsBy)} }>{this.props.count}</someElement>

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.

React/redux - passing actionCreators many levels deep

I'm wondering how other people are handling passing redux action creators from a smart top-level component down to many lower level dumb components without bloating their props definitions.
For example, following this excellent tutorial on redux, if I pass a list of action creators into the props like so
import Voting from './Voting';
import * as actionCreators from '../action_creators';
...
export const VotingContainer = connect(
mapStateToProps,
actionCreators
)(Voting);
then in my Voting component I have access to the actionCreators which is really cool.
But if I have say 20 actionCreators that are used in Voting and all of its child components, eg.
Voting -> VotingContainer -> VotingDetail -> VotingFoo -> VotingBar
then I end up with render functions that look like this
class Voting extends React.Component {
render(){
<VotingContainer
actionCreator1={this.props.actionCreator1}
.
.
.
actionCreator15={this.props.actionCreator15} />
}
}
class VotingContainer extends React.Component {
render(){
<VotingDetail
actionCreator1={this.props.actionCreator1}
.
.
.
actionCreator12={this.props.actionCreator12} />
}
}
.
.
.
class VotingFoo extends React.Component {
render(){
<VotingBar
actionCreator1={this.props.actionCreator1}
.
.
.
actionCreator6={this.props.actionCreator6} />
}
}
Is there a best practice for this situation, a way to group the actionCreators together somehow without a lot of boilerplate at each step ? I haven't seen anything in any of the tutorials/examples...
Just connect components below the tree to Redux too.
We over-emphasize “one container at the top” in the examples.
This makes sense when we’re talking about very simple apps.
For any complex app, as soon as passing props gets tedious, connect() components below.
I cover this in my free videos: see Extracting Container Components and the next several videos.
I find that in most cases where I have a lot of dumb wrappers around a core ui component, most of the props from the top container are needed in the most nested component.
Because of this, ES6 ... syntax helps a lot.
You can do this:
<VotingBar {...this.props} />
Which is equivalent to this:
<VotingBar
actionCreator1={this.props.actionCreator1}
.
.
.
actionCreator6={this.props.actionCreator6} />
To avoid passing propertied from level to level down to where those props are actually used, React Context could be used to wrap the top Child with context (some specific data).
Codepen Demo
Here's a simple use-case example, where more than one reducer is defined, each of the reducers is responsible for its own state (a counter in this example)
A <Button> is inside a <Modal> and two Modal components are inside App, each one should eventually "broadcast" the change made internally (in the deepest component) to the top component (App) which is actually listening to the changes and acting on them.
Only App cares about changes in Button but since there can be many Button components, the App must know which deep component did what action and dispatch the right data back to Redux.
The Modal is simply something in between which exists for representational purposes only. it doesn't care about any props or state. Button also doesn't care about anything except what is being sent to it directly via the Context. he listen to changes via the Consumer method from React.createContext
const { Provider:ContextProvider, Consumer:ContextConsumer } = React.createContext({});
const {connect, Provider } = ReactRedux;
const {createStore, compose, combineReducers} = Redux;
const {Component} = React;
//// REDUX STORE STUFF /////////////////////////////////////
function reducer_foo(state = {value:1}, action){
if( action.type == 'FOO__SET_VALUE') // type should be unique
return { ...state, value:action.value }
else return state
}
function reducer_bar(state = {value:1}, action){
if( action.type == 'BAR__SET_VALUE') // type should be unique
return { ...state, value:action.value }
else return state
}
const rootReducer = combineReducers({
foo: reducer_foo,
bar: reducer_bar
});
//// REACT STUFF /////////////////////////////////////
// 2nd depth-level
// This component's "job" is to simply take a value and return a manipulated value to
// whoever called it. This is a very simplifed component, but think of a datepicker instead.
const Button = () =>
<ContextConsumer>
{v => <button onClick={()=> v.action(v.value + 1, v.name)}>Click to INC: {v.value}</button>}
</ContextConsumer>
// 1st depth-level (in reality this level will be more complex)
const Modal = () => <p><Button /></p>
// top depth-level component
class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
// The deepest component will pass the value and the name for which to dispatch to
updateValue = ( value, name ) => {
this.props.dispatch({type:`${name.toUpperCase()}__SET_VALUE`, value})
}
render(){
const {foo, bar} = this.props;
return (
<React.Fragment>
<ContextProvider value={{value:foo.value, action:this.updateValue, name:'foo'}}>
<Modal />
</ContextProvider>
<ContextProvider value={{value:bar.value, action:this.updateValue, name:'bar'}}>
<Modal />
</ContextProvider>
</React.Fragment>
)
}
}
function mapStateToProps(state){
return state // in this example let's just pass the whole state for simplicity
}
const ConnectedApp = connect(mapStateToProps)(App)
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<ConnectedApp />
</Provider>,
document.getElementById('root')
)
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.7/react-redux.min.js"></script>
<div id="root"></div>
There are of course a variety of ways you can tackle this issue.
Recently, I've started skipping the whole passing of action creator functions down the chain in favor of just requiring the store and my action creators directly wherever they're needed and dispatching from there, e.g.
var store = require('../store');
var actions = require('../actions');
// Somewhere inside your component...
store.dispatch(actions.someAction(data));
Just make sure the result of your action creators (i.e. the new state) is passed down through your top level components. This keeps your data flow unidirectional and easy to understand.

Resources