React pass data from mapped child to new component - reactjs

I have a shopping catalog, I want to get data from the child and pass to a new component. I've mapped data from JSON (later to be an api call) and I want to get a few props from the mapped child component ie name, price, and the count (which is part of the component, not the original data)
data(name/price) -> mainComponent -> mapped to childComponent(has count)-> mainComponent
should I be using forms? some lifecycle methods? redux? Router? not really sure how to go about this.
Data
const marketData = [
{
id: 1,
name: "product1",
price: "$2",
},
{
id: 2,
name: "product2",
price: "$3",
},
{
id: 2,
name: "product3",
price: "$3",
}
]
Parent
import React, { Component } from 'react';
import MarketItem from './MarketItem.js'
import MarketData from './MarketData.js'
class MarketContainer extends Component {
constructor() {
super()
this.state = {
market: MarketData
}
}
render() {
const marketItems = this.state.market.map(item => <MarketItem key={item.id} product={item} />)
return (
<div>
{marketItems}
</div>
);
}
}
export default MarketContainer;
child
import React, {Component} from 'react';
class MarketItem extends Component {
constructor(props){
super(props)
this.state = {
count : 0
}
}
IncrementItem = () => {
this.setState({ count: this.state.count + 1 });
}
IncrementItemBy10 = () => {
this.setState({ count: this.state.count + 10 });
}
render(){
return (
<div className="MarketItem">
<div className="market__content">
<h1>{this.props.product.name + " " + this.props.product.price}</h1>
</div>
<div className="market__counter">
<button className="market__button--minus" onClick={this.DecreaseItem}>-</button>
<p>{this.state.count}</p>
<button className="market__button--plus" onClick={this.IncrementItem}>+</button>
</div>
</div>
);
}
}
export default MarketItem;
Within parent (marketContainer) I want to get the count, name, and price from every child component, make a new component. I've tried forms, but wasn't really happy with that should I use lifecycle methods? redux? Router?

class MarketContainer extends Component {
state = {
count : 0
}
IncrementItem = () => {
this.setState({count: count + 1})
}
DecreaseItem = () => {
this.setState({count: count - 1})
}
render() {
const marketItems = this.state.market.map(item => <MarketItem key={item.id}
product={item} IncrementItem={this.IncrementItem} DecreaseItem={DecreaseItem} count={this.state.count}/>)
return (
<div>
{marketItems}
</div>
);
}
}
now you can use IncrementItem and DecreaseItem props on MarketItem component when user click on increment and decrement icon. also we're passing value of count from parent component so you can show in child component.

You need to use Lifting State Up in React

You can define the state in MarketContainer for counts and other fields that you need to pass to other child components.
I have tried to include the codes to illustrate how I would do that.
//MarketData.js
//after ajax request
const marketData = [
{
id: 1,
name: "product1",
price: "$1"
},
{
id: 2,
name: "product2",
price: "$2"
}
];
//We can format market data as per we need it in components
const formattedMarketData = marketData.map(e => {
e.count = 0;
return e;
});
//parent component
//let us define all the things which we might need to pass to other components in here
// ...
constructor()
{
super();
this.state = {
markets: formattedMarketData
}
}
/* we are handling all state changes in parent component
we have updated state in parent component
we can deliver the changed state to any other components */
IncrementItem = (id) => {
this.setState((prevState) => {
const markets = {...prevState.markets};
const index = markets.findIndex(x => x.id ===id);
markets[index].count = prevState.markets[index].count + 1;
return {
markets: markets
};
});
}
DecrementItem = (id) => {
this.setState((prevState) => {
const markets = {...prevState.markets};
const index = markets.findIndex(x => x.id ===id);
markets[index].count = prevState.markets[index].count - 1;
return {
markets: markets
};
});
}
render() {
const marketItems = this.state.market.map(item => <MarketItem IncrementItem={this.IncrementItem} DecrementItem={this.DecrementItem} key={item.id} product={item} />)
return (
<div>
{marketItems}
</div>
);
}
//child component
export default (props) => {
const {IncrementItem, DecreaseItem, product} = props;
<div className="MarketItem">
<div className="market__content">
<h1>{product.name + " " + product.price}</h1>
</div>
<div className="market__counter">
<button className="market__button--minus" onClick={() => {DecreaseItem(product.id)}}>-</button>
<p>{product.count}</p>
<button className="market__button--plus" onClick={() => {IncrementItem(product.id)}}>+</button>
</div>
</div>
};

I think this is the way you should design your state to keep the count relevant to the products.
import React, { Component } from 'react';
import MarketItem from './MarketItem.js'
class MarketContainer extends Component {
constructor() {
super()
this.state = {
market: [
{
id: 1,
name: "product1",
price: "$2",
count:0,
},
{
id: 2,
name: "product2",
price: "$3",
count:0,
},
{
id: 2,
name: "product3",
price: "$3",
count:0,
}
]
}
}
IncrementItem = (i) => {
let market = this.state.market;
market[i].count += 1;
this.setState({market});
}
DecreaseItem = (i) => {
let market = this.state.market;
market[i].count -= (market[i].count > 0) ? 1: 0;
this.setState({market});
}
render() {
const marketItems = this.state.market.map(item => <MarketItem key={item.id} product={item} i={i} IncrementItem={this.IncrementItem} DecreaseItem={this.DecreaseItem}/>)
return (
<div>
{marketItems}
</div>
);
}
}
export default MarketContainer;
child
import React, {Component} from 'react';
class MarketItem extends Component {
constructor(props){
super(props);
}
render(){
return (
<div className="MarketItem">
<div className="market__content">
<h1>{this.props.product.name + " " + this.props.product.price}</h1>
</div>
<div className="market__counter">
<button className="market__button--minus" onClick={() => this.props.DecreaseItem(this.props.i)}>-</button>
<p>{this.state.count}</p>
<button className="market__button--plus" onClick={() => this.props.IncrementItem(this.props.i)}>+</button>
</div>
</div>
);
}
}
export default MarketItem;

Related

My checkbox is not changing from check or uncheck, but I can see that state value is changing, what's going on?

So when I run this and check the checkbox, I can see the values changing in the state, but why is the checkbox control not changing its status from check/uncheck? I know the render() method is being hit as well. Why, oh why, Gods of code? Lost in hours of figuring out what's wrong and I'm lost!
bob-Todos.js FILE
class Todo extends React.Component {
constructor(param) {
super();
this.state = {
id: param.data.id,
text: param.data.text,
completed: param.data.completed,
onMyChange: param.OnChange,
};
}
render() {
console.log("In TODO Render");
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
this.state.onMyChange(this.state.id);
}}
checked={this.state.completed}
/>
{this.state.text}
</p>
</div>
);
}
}
export default Todo;
Bob-App.js FILE
import React, { Component } from "react";
import Todo from "./bob-Todo";
import todoData from "../data/bob-todosData";
class App extends Component {
constructor() {
super();
this.state = { data: todoData };
this.OnChange = this.OnChange.bind(this);
}
OnChange(myId) {
this.setState((prev) => {
let updatedTodos = prev.data.map((todo) => {
if (todo.id === myId) {
todo.completed = !todo.completed;
}
return todo;
});
return { data: updatedTodos };
});
console.log(this.state.data);
}
render() {
return this.state.data.map((item) => {
return <Todo key={item.id} data={item} OnChange={this.OnChange} />;
});
}
}
export default App;
bob-todosData.js FILE
const todosData = [
{
id: 1,
text: "take out the trash",
completed: true
},
{
id: 2,
text: "rest for a while and relax",
completed: false
},
{
id: 3,
text: "watch an online movie",
completed: true
}
]
export default todosData
index.js FILE
import React from 'react';
import ReactDOM from 'react-dom';
import AppBob from "./bobComponents/Bob-App";
ReactDOM.render(
<AppBob />, document.getElementById('root')
);
You don't need to assign your props to state in your Todo component
Just remove them and invoke the function also use those variables directly:
Then your component will be:
class Todo extends React.Component {
render() {
const {
data: {
id,
text,
completed,
},
OnChange, // <-- Should rename this to "onChange"
} = this.props;
console.log('In TODO Render');
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
OnChange(id);
}}
checked={completed}
/>
{text}
</p>
</div>
);
}
}
export default Todo;
Also, rename your OnChange function to onChange to enable js convention

Passing props to Parent component

I am really novice to React and I am stuck with this one.
I want to pass data from NewAction component to its parent NewActionSet.
I dont know what i am missing.
I am developing an on-boarding platform with a lot a components and I aim to send all the data entered into all the components to a server.
React parent Component:
import React from 'react'
import './NewActionSet.css'
import axios from 'axios'
import { Container, Segment, Header, Input } from 'semantic-ui-react'
import NewAction from './NewAction'
import 'bootstrap/dist/css/bootstrap.min.css'
class NewActionSet extends React.Component {
constructor (props) {
super(props)
this.state = {
actions: [],
actionType: '',
actionValue: '',
creationStatus: undefined
}
}
handleActions = value => {
this.setState({
actionsList: value
})
console.log(this.state.actionsList)
}
handleSubmit = event => {
event.preventDefault()
console.log(this.state)
axios
.post(
'/assistant/actions/',
{ ...this.state.values },
{ headers: {
xsrfHeaderName: 'X-CSRFToken',
xsrfCookieName: 'csrftoken'
},
withCredentials: true
}
)
.then(response => {
console.log(response)
this.setState({
creationStatus: true
})
})
.catch(error => {
console.log(error)
this.setState({
creationStatus: false
})
})
}
addNewAction = () => {
let { actions } = this.state
this.setState({
actions: [...actions, <NewAction onNewAction={this.handleActionstoParent} />]
})
}
handleActionstoParent = (action2Value, selectedAction) => {
this.setState({
actionType : selectedAction,
actionValue : action2Value
})
// console.log(this.state.actionType, this.state.actiondValue)
}
renderActions () {
return this.state.actions.map((action, index) => {
return (
<NewAction
key={index}
type={this.props.actionType}
content={action.content}
onNewAction={this.handleActionstoParent}
/>
)
})
}
render () {
let index = 0
return (
<Container>
<Header> Action sets </Header>
<Header color='grey' as='h3'>
SET #{index + 1}
</Header>
{this.renderActions()}
<button onClick={() => this.addNewAction()}> New Action </button>
</Container>
)
}
}
export default NewActionSet
React child component
import React from 'react'
import './NewActionSet.css'
import { Header, Dropdown } from 'semantic-ui-react'
import NewSpeechText from './NewSpeechText'
import NewAddPageURL from './NewAddPageURL'
import 'bootstrap/dist/css/bootstrap.min.css'
class NewAction extends React.Component {
constructor (props) {
super(props)
this.state = {
availableActions: [
{ key: 1, text: 'Navigate to page', value: 'Navigate to page' },
{ key: 2, text: 'Play speech', value: 'Play speech' }
],
selectedAction: '',
actionValue: '',
currentElement: ''
}
}
handleActionURL = (value) => {
this.setState({
actionValue: value
})
console.log(this.state.selectedAction, this.state.actionValue)
}
handleActionSpeech = (value) => {
this.setState({
actionValue: value
})
console.log(this.state.selectedAction, this.state.actionValue)
}
// Props to pass data to parent component --> NewActionSet.js
handleActionstoParent = (selected) => {
var action2Value = this.state.actionValue;
console.log(action2Value)
var action2Type = this.state.actionType
this.props.onNewAction(action2Value, action2Type)
console.log(action2Type)
// console.log(this.state.actionValue, this.state.selectedAction)
}
handleChange = (e, { value }) => {
let element
this.setState({
selectedAction: value
})
if (value === 'Navigate to page') {
element = <NewAddPageURL onNewAddPageURL={this.handleActionURL} onChange={this.handleActionstoParent()} />
} else if (value === 'Play speech') {
element = <NewSpeechText onNewSpeechText={this.handleActionSpeech} onChange={this.handleActionstoParent()} />
}
this.setState({
currentElement: element
})
}
render () {
const { value } = this.state
let index = 0
return (
<div className='action'>
<div className='container'>
<Header color='grey' as='h4'>
ACTION #{index + 1}
</Header>
<div className='row'>
<div className='col-md-4'>
<Dropdown
onChange={this.handleChange}
options={this.state.availableActions}
placeholder='Choose an action'
selection
value={value}
/>
</div>
<div className='col-md-4' />
<div className='col-md-4' />
</div>
<div style={{ marginBottom: '20px' }} />
{this.state.currentElement}
</div>
</div>
)
}
}
export default NewAction
Can you please assist?
Thanks a lot
The handleActionstoParent function in NewAction component is the problem.
When you send data from child to parent, actually the data is not updated data.
// Props to pass data to parent component --> NewActionSet.js
handleActionstoParent = (e) => {
this.setState({ [e.target.name]: e.target.value }, () => {
var action2Value = this.state.actionValue;
var action2Type = this.state.actionType;
this.props.onNewAction(action2Value, action2Type);
});
}
You could pass a function to NewAction, in example below we pass handleDataFlow function to our child component and then use it in our child component to pass data higher:
import React from 'react'
import './NewActionSet.css'
import { Header, Dropdown } from 'semantic-ui-react'
import NewSpeechText from './NewSpeechText'
import NewAddPageURL from './NewAddPageURL'
import 'bootstrap/dist/css/bootstrap.min.css'
class NewAction extends React.Component {
constructor (props) {
super(props)
this.state = {
availableActions: [
{ key: 1, text: 'Navigate to page', value: 'Navigate to page' },
{ key: 2, text: 'Play speech', value: 'Play speech' }
],
selectedAction: '',
actionValue: '',
currentElement: ''
}
}
handleActionURL = (value) => {
this.setState({
actionValue: value
})
console.log(this.state.selectedAction, this.state.actionValue)
}
handleActionSpeech = (value) => {
this.setState({
actionValue: value
})
console.log(this.state.selectedAction, this.state.actionValue)
}
// Props to pass data to parent component --> NewActionSet.js
handleActionstoParent = (selected) => {
var action2Value = this.state.actionValue;
console.log(action2Value)
var action2Type = this.state.actionType
this.props.onNewAction(action2Value, action2Type)
console.log(action2Type)
// console.log(this.state.actionValue, this.state.selectedAction)
}
handleChange = (e, { value }) => {
let element
this.setState({
selectedAction: value
})
this.props.handleDataFlow(value)
if (value === 'Navigate to page') {
element = <NewAddPageURL onNewAddPageURL={this.handleActionURL} onChange={this.handleActionstoParent()} />
} else if (value === 'Play speech') {
element = <NewSpeechText onNewSpeechText={this.handleActionSpeech} onChange={this.handleActionstoParent()} />
}
this.setState({
currentElement: element
})
}
render () {
const { value } = this.state
let index = 0
return (
<div className='action'>
<div className='container'>
<Header color='grey' as='h4'>
ACTION #{index + 1}
</Header>
<div className='row'>
<div className='col-md-4'>
<Dropdown
onChange={this.handleChange}
options={this.state.availableActions}
placeholder='Choose an action'
selection
value={value}
/>
</div>
<div className='col-md-4' />
<div className='col-md-4' />
</div>
<div style={{ marginBottom: '20px' }} />
{this.state.currentElement}
</div>
</div>
)
}
}
export default NewAction
Data flow in React is unidirectional. Data has one, and only one, way to be transferred: from parent to child.
To update parent state from child you have to send action (in props).
<NewAction updateParentState={this.doSmth} />
...
const doSmth = params => { this.setState({ ... })
and in NewAction you can call it in specific case
let parentUpdateState = ....
this.props.updateParentState(parentUpdateState);

How do I manage my array of children components' states?

I'm new to react, so forgive me. I'm having a problem understanding states, specifically those of children.
Purpose: I'm trying to create a form that a user can append more and more components -- in this case, images.
What happens: User appends 2 or more images. User tries to upload an image with UploadButton component, but both the images are the same. I believe this has to do with both appended children sharing the same state.
Question: How do I give each appended child its own image without affecting the other appended children?
class Page extends Component
constructor (props) {
super(props);
this.state = {
id: '',
numChildren: 0,
images: [],
}
this.onAddChild = this.onAddChild.bind(this);
}
showModal() {
this.setState({
numChildren: 0,
images: [],
});
}
renderModal()
const children = [];
//Here's my array of child components
for(var i = 0; i < this.state.numChildren; i += 1) {
children.push(<this.ChildComponent key={i} />);
}
return (
<ReactModal>
<this.ParentComponent addChild={this.onAddChild}>
{children}
</this.ParentComponent>
</ReactModal>
)
}
onAddChild = () => {
this.setState({
numChildren: this.state.numChildren + 1
})
}
ParentComponent = (props) => (
<div>
{props.children}
<Button onClick={props.addChild}>Add Item</Button>
</div>
);
ChildComponent = () => (
<div>
<UploadButton
storage="menus"
value={this.state.images}
onUploadComplete={uri => this.setState({images: uri})}
/>
</div>
);
}
Here's the code for UploadButton:
import React, { Component } from 'react';
import uuid from 'uuid';
import firebase from '../config/firebase';
class UploadButton extends Component {
constructor(props) {
super(props);
this.state = {
isUploading: false
}
}
handleClick() {
const input = document.createElement("INPUT");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/gif, image/jpeg, image/png");
input.addEventListener("change", ({target: {files: [file]}}) => this.uploadFile(file));
input.click();
}
uploadFile(file) {
console.log('F', file);
const id = uuid.v4();
this.setState({ isUploading: true })
const metadata = {
contentType: file.type
};
firebase.storage()
.ref('friends')
.child(id)
.put(file, metadata)
.then(({ downloadURL }) => {
this.setState({ isUploading: false })
console.log('Uploaded', downloadURL);
this.props.onUploadComplete(downloadURL);
})
.catch(e => this.setState({ isUploading: false }));
}
render() {
const {
props: {
value,
style = {},
className = "image-upload-button",
},
state: {
isUploading
}
} = this;
return (
<div
onClick={() => this.handleClick()}
className={className}
style={{
...style,
backgroundImage: `url("${this.props.value}")`,
}}>
{isUploading ? "UPLOADING..." : !value ? 'No image' : ''}
</div>
);
}
}
export default UploadButton;
I tried to exclude all unnecessary code not pertaining to my problem, but please, let me know if I need to show more.
EDIT: This is my attempt, it doesn't work:
//altered my children array to include a new prop
renderModal() {
const children = [];
for (var i = 0; i < this.state.numChildren; i += 1) {
children.push(<this.ChildComponent imageSelect={this.onImageSelect} key={i} />);
}
//...
};
//my attempt to assign value and pass selected image back to images array
ChildComponent = () => (
<div>
<UploadButton
storage="menus"
value={uri => this.props.onImageSelect(uri)} //my greenness is really apparent here
onUploadComplete={uri => this.setState({images: uri})}
/>
//...
</div>
);
//added this function to the class
onImageSelect(uri) {
var el = this.state.images.concat(uri);
this.setState({
images: el
})
}
I know I'm not accessing the child prop correctly. This is the most complexity I've dealt with so far. Thanks for your time.
When you write this.state in Child / Parent component, you are actually accessing the state of Page. Now, I would recommend that you pass in the index of the child to the Child like so
children.push(<this.ChildComponent key={i} index={i}/>)
so that each children deals with only its own image like so
ChildComponent = ({index}) => (
<div>
<UploadButton
storage="menus"
value={this.state.images[index]}
onUploadComplete={uri => {
let images = this.state.images.slice()
images[index] = uri
this.setState({images})
}}
/>
</div>
);

Why is my react component not updating?

I have a simple Cart component and I want to show either a "Your cart is empty" message when there are no items in it.
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as CartActions from '../actions/cart'
import Shelf from './Shelf'
import EmptyCart from './EmptyCart'
/*
This is a container component
*/
class Cart extends Component {
constructor(props) {
super(props)
this.state = {
itemQuantity: props.cart.length
}
}
render() {
const CartItems = this.props.cart.map(
(item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
)
const isCartEmpty = () => this.state.itemQuantity === 0
console.log("is cart empty? ", isCartEmpty(), "cart item quantity ", this.state.itemQuantity)
return(
<div className="Cart">
<Shelf addItem={this.props.action.addToCart} />
<h2>Cart Items</h2>
<ol>
{ isCartEmpty() ? <EmptyCart/> : {CartItems} }
</ol>
</div>
)
}
}
function mapStateToProps(state, prop) {
return {
cart: state.cart
}
}
function mapDispatchToProps(dispatch) {
return {
action: bindActionCreators(CartActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Cart)
My Shelf component looks like this:
import React, { Component } from 'react';
class Shelf extends Component {
constructor(props) {
super(props)
this.addItemToCart = this.addItemToCart.bind(this)
this.state = {
shelfItems: [
{ "name": 'shampoo', "price": 23 },
{ "name": 'chocolate', "price": 15 },
{ "name": 'yogurt', "price": 10 }
]
}
}
addItemToCart(item){
this.props.addItem(item)
}
render() {
const shelfItems = this.state.shelfItems.map((item, idx) => {
return <li key={idx}><button onClick={()=>this.addItemToCart(item)}>[+]</button>{item.name} - ${item.price}</li>
})
return(
<div>
<h2>Shelf</h2>
<ul>
{shelfItems}
</ul>
</div>
)
}
}
export default Shelf
Cart Reducer:
export default(state = [], payload) => {
switch (payload.type) {
case 'add':
return [...state, payload.item]
default:
return state
}
}
addToCart action:
export const addToCart = (item) => {
return {
type: 'add',
item
}
}
The empty message shows up but the list does not update when I add items. What am I doing wrong? The code works just fine if I remove the conditionals and just render CartItems
It's because you set only initial state. When you add item you don't set a new state. If you use redux there is no local state needed.
Try this:
class Cart extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
const CartItems = this.props.cart.map(
(item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
)
const isCartEmpty = CartItems.length === 0
return(
<div className="Cart">
<Shelf addItem={this.props.action.addToCart} />
<h2>Cart Items</h2>
<ol>
{isCartEmpty ? <li>Your Cart is Empty</li> : CartItems}
</ol>
</div>
)
}
}

My component isn't updating, am I mutating the state?

I have a container component that connects to the state which I made with immutable.js. When I update the state, my redux inspector tells me that the state is updated, but my component doesn't get the new updates and doesn't re-render.
My container component:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { setCategoryActive } from '../actions'
import Category from '../components/Category'
class MenuList extends Component {
constructor(props) {
super(props)
this.categories = this.props.categories
this.subreddits = this.props.subreddits
this.allCategories = this.categories.get("allCategories")
this.byName = this.categories.get("byName")
}
printSubreddits(category) {
const subreddits = this.byName.get(category)
const subredditsByName = subreddits.get("subredditsByName")
const list = subredditsByName.map((subreddit, i) => {
return <p className="swag" key={i}>{subreddit}</p>
})
return list
}
isCategoryActive(category) {
const cat = this.byName.get(category)
return cat.get("active")
}
printCategory(category, i) {
console.log(this.isCategoryActive(category))
return (
<div className="category-container" key={i}>
<Category name={category}
active={this.isCategoryActive(category)}
setActive={this.props.setCategoryActive.bind(this, category)} />
{this.isCategoryActive(category) ? this.printSubreddits(category) : null}
</div>
)
}
render() {
return (
<div>
{this.allCategories.map((category, i) => {
const x = this.printCategory(category, i)
return x
}, this)}
</div>
)
}
}
const mapStateToProps = (state) => ({
categories: state.subredditSelector.get('categories'),
subreddits: state.subredditSelector.get('subreddits')
})
export default connect(mapStateToProps, {
setCategoryActive
})(MenuList);
My Category component
class Category extends Component {
printToggle(active) {
if (active) {
return <span> [-]</span>
} else {
return <span> [+]</span>
}
}
componentWillReceiveProps(nextProps) {
this.printToggle(nextProps.active)
}
render() {
const { setActive, active, name } = this.props
return (
<div className="category-container">
<a onClick={setActive}
href="#"
className="category-title">
{name}
{this.printToggle(active)}
</a>
</div>
)
}
}
export default Category
And my reducer
import { fromJS } from 'immutable'
import {
SET_SUBREDDIT_ACTIVE,
SET_CATEGORY_ACTIVE
} from '../actions'
import List from '../data/nsfw_subreddits.js'
const initState = fromJS(List)
const subredditSelector = (state = initState, action) => {
switch (action.type) {
case SET_SUBREDDIT_ACTIVE:
return state
case SET_CATEGORY_ACTIVE:
return state.updateIn(['categories', 'byName', action.payload.name],
x => x.set('active', !x.get('active')))
default:
return state
}
}
export default subredditSelector
A piece of my state that I have coded as a JSON object
const list = {
categories: {
byName: {
"example": {
name: "example",
id: 1,
active: true,
subredditsByName: ["example", "example"]
},
"example": {
name: "example",
id: 2,
active: true,
subredditsByName: ["example"]
},
"example": {
name: "example",
id: 3,
active: true,
subredditsByName: ["example", "example", "example"]
}
},
allCategories: ["example", "example", "example"]
},
subreddits: {
My guess is that my reducer is mutating the state? Though I am not sure how, since I am using the immutable js functions?
So I fixed this issue by changing the constructor from a constructor to a regular function and called it at the top of my render method!
You should still keep your constructor, but only have in it what needs to be done when the object is first created:
constructor(props) {
super(props)
}
And yes, having
cleanPropData(){
this.categories = this.props.categories
this.subreddits = this.props.subreddits
this.allCategories = this.categories.get("allCategories")
this.byName = this.categories.get("byName")
}
is fine. I haven't heard of someone invoking it at the top of a render function. Nice to know that works.

Resources