React-Redux - Using multiple container decorators - reactjs

I have 3 containers:
UserTask
UserMsg
UserNotify
Each have their own page in the app, but on the main page there is a drop down displaying all container data. Here is how I decorated the dropdown component:
#UserTaskContainer
#UserMessageContainer
#UserNotifyContainer
class ActivitiesDropdown extends React.Component {
....
componentWillMount() {
const allProps = this.props;
}
....
}
exports.ActivitiesDropdown = ActivitiesDropdown;
When debugging, all load data successfully and I see each's data being added to state, but in the ComponentWillMount, only the data from Notification state is present.
It appears, if I switch the decorators around, which ever is the last decorator is the one that shows up in props.
Question:
If I have a component that has multiple containers, how can I use the decorators to get all the states' props, or is there another way to acheive this?
Thanks in Advance.

Related

Where to keep active user data on React + Redux client application

On my React + Redux client app, I need to get the active user info (fetch from myapp.com/users/me) and keep it somewhere so that I can access it from multiple components.
I guess window.activeUser = data would not be the best practice. But I could not find any resource about the best practice of doing that. What would be the best way to do what I want?
you can keep it in a separate reducer, and then import multiple parts of your state with connect() in your components.
Say if you have 2 reducers called users.js and tags.js which are combined with combineReducers when setting up your store. You would simply pull different parts by passing a function to your connect() call. So using es6 + decorators:
const mapStateToProps = state => {
return {users: state.users, tags: state.tags}
}
#connect(mapStateToProps)
export default class MyComponent extends React.Component {
and then down in your render function:
return (
<div>
<p>{this.props.users.activeUsernameOrWhatever}</p>
<p>{this.props.tags.activeTags.join('|')}</p>
</div>
);
So your different reducer states become objects on this.props.
You can use React's context, HOC or global variables to make your data available to multiple components, via context
Something like...
class ParentDataComponent extends React.Component {
// make data accessible for children
getChildContext() {
return {
data: "your-fetchet-data"
};
}
render() {
return < Child />
}
}
class Child extends React.Component {
render() {
// access data from Parent's context
return (<div> {this.context.data} </div>);
}
}
create an action creator and call it on componentWillMount of the appropriate component so it runs right before your component mounts, and in the action creator fetch the data you need and pass it to a reducer. in that reducer you can keep the data you want throughout your application. so whenever you needed the data you can retrieve it from redux state. this tutorial from official redux website covers everything you need to know. mention me if you had any questions.

flux multiple components in same page are influenced with each other, bugs

I am using same component multiple times in the same page, and I just realized that any event dispatched are intercepted by all the same companents and all the components are updated together.
This is not acceptable, as even if it is same component, if it is used to display different data, they should have totally independent behavior. Action performed in one component should never be listened by another component.
How can I fix this error?
You should have a container component which will get a data collection, which represents the component you are repeating. An action will change that data collection, and not the repeated component itself. In other words, the repeated component should not get data directly from the store.
You could see an full todomvc example, which has the same "TodoItem" component being rendered a few times in one page here: TodoMVC example
Example:
var ButtonStore = require('../stores/ButtonStore');
function getButtonState() {
return {
allButtons: ButtonStore.getAll()
}
}
const Button = (props) => {
return <button>{props.text}</button>
}
class ButtonList extends React.Component {
constructor(props) {
super(props)
this.state = getButtonState()
}
render() {
return <div>
{this.state.allButtons.map(button => <Button {...button} />)}
</div>
}
}
Here is a fiddle of the example, just without the store: Component List Example
It could be helpful, if you post some code example.

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.

Using a method on a React class from a separate component

On the home page of my site, you can click a menu button that triggers a method which toggles a menu. This changes the state from menuOpen from false to true.
On a different page, I click a 'back' button, and it should go to the home route, but open this menu when the page has loaded rather than when I click. Currently all I have is:
handleBack(){
App.navigate('/');
}
Can I import the component and call its method? Or can I set up a new React Router route that somehow executes the state change? Or is there another way around it?
Redux would help, but since I'm guessing you're not using that OR you don't want to refactor your entire application to set this one boolean, I'd recommend using a higher order component.
So for example, you'd define a higher-order component (think superclass) like this:
export function menuToggler(ComposedComponent) {
return class extends React.Component {
toggleMenuBoolean() {
// code here
},
render() {
return <ComposedComponent toggleMenuBoolean={toggleMenuBoolean} {...this.props} />
}
};
}
Then, in your regular component, you simply wrap it with the higher order component. So if previously, you were using ES6 and exporting your component like this:
export default MyComponent;
It would then become:
export default menuToggler(MyComponent);
From there, you can invoke this toggleMenuBoolean function from any component that is wrapped by your higher order component by simply calling it on props:
this.props.toggleMenuBoolean(false), etc.
More reading here:
https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750#.sh6m9c9ct
If you want that scenario, pass the state value to the parent component which is a 'smart component' manages dumb componenets. Or you can use 'flux' / 'redux'.

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