Redux: One container for many components

I am new to React and Redux, and I am currently working on a project where I am unsure of the best practices and technical solutions. I am following Dan Abramov's definitions of "smart" and "dumb" components which can be found here.

The component I am developing consists of a few filter components: an input text field and two buttons which filter a list of entities. I have experimented with two different approaches:

First approach: A single component containing three instances of two types of containers that are connected to corresponding components.

This was my initial solution. The root component is structured like this:

import React, { PropTypes, Component } from 'react';
import Config from '../../config';
import FilterInput from '../containers/FilterInput';
import FilterLink from '../containers/FilterLink'

class FilterController extends Component {
    render() {
        return (
            <div className='filterController'>
                <FilterInput displayName="Search" filterName={Config.filters.WITH_TEXT} />
                <FilterLink displayName="Today" filterName={Config.filters.IS_TODAY} />
                <FilterLink displayName="On TV" filterName={Config.filters.ON_TV} />
            </div>
        )
    }
}
export default FilterController;

The two containers used in this approach look as expected, as do the connected components. An example is the FilterLink component:

import React, { PropTypes, Component } from 'react';
import {connect} from 'react-redux';
import {toggleFilter} from '../actions';
import FilterButton from '../components/filterbutton'

const mapStateToProps = (state, ownProps) => {
    return {
        active: !!state.program.filters[ownProps.filterName]
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        onClick: () => {
            dispatch(toggleFilter(ownProps.filterName, ownProps.input))
        }
    }
}

const FilterLink = connect(
    mapStateToProps,
    mapDispatchToProps
)(FilterButton)

export default FilterLink

And here is the corresponding FilterButton component:

import React, { PropTypes, Component } from 'react';

class FilterButton extends Component {

    render() {
        return (
            <button className={this.props.active ? 'active' : ''}
                    onClick={this.props.onClick}>
                {this.props.displayName}
            </button>
        )
    }
}

FilterButton.propTypes = {
    active: PropTypes.bool.isRequired,
    displayName: PropTypes.string.isRequired,
    onClick: PropTypes.func.isRequired,
    filterName: PropTypes.string.isRequired
};

export default FilterButton;

Although this approach works, I believe there may be a more efficient way to handle the containers. This led me to try a second approach.

Second approach: A single container for multiple components.

In this case, I created a larger container:

import React, { PropTypes, Component } from 'react';
import Config from '../../config';
import {connect} from 'react-redux';
import {toggleFilter} from '../actions';
import FilterButton from '../components/filterbutton'
import FilterInput from '../components/filterinput'

class FilterContainer extends Component {
    render() {
        const { active, currentInput, onChange, onClick } = this.props;
        return (
            <div className='filterController'>
                <FilterInput displayName="Search" filterName={Config.filters.WITH_TEXT} currentInput={currentInput} onChange={onChange} />
                <FilterButton displayName="Today" filterName={Config.filters.IS_TODAY} active={active} onClick={onClick}/>
                <FilterButton displayName="On TV" filterName={Config.filters.ON_TV} active={active} onClick={onClick}/>
            </div>
        )
    }
}

const mapStateToProps = (state, ownProps) => {
    return {
        active: !!state.program.filters[ownProps.filterName],
        currentInput: state.program.filters[ownProps.filterName] ? state.program.filters[ownProps.filterName].input : ''
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        onClick: () => {
            dispatch(toggleFilter(ownProps.filterName, ownProps.input))
        },
        onChange: newValue => {
            dispatch(toggleFilter(ownProps.filterName, newValue.target.value))
        }
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(FilterContainer);

In this setup, all state management for the component is handled within a single component. The components used here are the same as in the first approach. However, I encountered an issue - ownProps appears to be empty in both mapStateToProps and mapDispathToProps. It seems I may have misunderstood how the react-redux connection operates.

Based on these experiments, I have two questions: What is the optimal way to structure this component in terms of containers and components? And why does ownProps not work similarly in the second approach as it did in the first?

Thank you for your assistance.

Answer №1

Currently, I don't have a clear answer when it comes to structure. The term "ownProps" refers to the props that are specifically passed into a component by its parent. Since you're using `connect()` with FilterController, this means that "ownProps" would be coming from wherever you render that component, such as: `return `.

Considering how your map functions are written, it seems like you actually want to connect the FilterInput and FilterButton components instead of FilterController.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Discover the steps to efficiently utilize the lookup feature with array objects in MongoDB

I am a beginner with MongoDB and I am trying to create a schema for my collection as shown below please note that all ObjectId values are placeholders and not real stockIn documents { serial:"stk0001", date:'2021-06-11', productInTra ...

Retrieve a file from a remote server without storing it locally on the server

I need to download a zip file from another server without saving it locally. Currently, I am sending a POST request to the server which responds with the zip file, then I save it on my local server and send it using res.download. What I would like is to di ...

Utilize a button within a form to add additional variables to a URL that already contains variables from a separate form

I operate a website that features a search bar and checkboxes for adding variables to the URL: term = "test" variable1=1 url/search?term=test&variable1=1 After completing the initial search, I have additional forms on the left side of the page with m ...

What do you do when schema.parseAsync cannot be found?

Currently facing an issue with zod validation in my Node.js environment, specifically encountering the error: TypeError: schema.parseAsync is not a function Despite attempting various solutions like re-importing and troubleshooting, I am unable to resol ...

React: Improve performance by optimizing the use of useContext to prevent unnecessary re-renders of the entire app or efficiently share data between components without causing all

In my app, I have a Header.tsx component that needs to be accessible on all pages and a Home.tsx component where most of the content resides. The Home.tsx component includes an intersectionObserver that utilizes the useContext hook (called homeLinks) to p ...

various locations within a hexagonal zone or figure

In my project, I am working with a simple hexagonal grid. My goal is to select a group of hexagons and fill them with random points. Here is the step-by-step process of generating these points: I start by selecting hexagons using a list of hex coordinat ...

ReactJS - run a JavaScript snippet once the Ajax call has successfully fetched and displayed the data

Where is the optimal placement for JavaScript code in order to execute a plugin after rendering is complete? <html> <head> <script src='https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.2.2/es6-promise.min.js'></script ...

steps for signing up and keeping the parameters current

I am currently working on an app using React Native built with Expo. I have been trying to register and update some columns, but I am encountering issues. Below is a snippet of my source code: import * as Location from 'expo-location'; const UR ...

Ways to verify the existence of browser sessions when dealing with multiple instances of a browser

In the after Each function, I need to check if browser sessions exist for each instance of the browser being used. If a browser is closed, special tear down logic specific to the app needs to be added by verifying the browser session. ...

What is the best method for sending a PHP variable to an AJAX request?

I am working with three files - my main PHP file, functions.php, and my JS file. My challenge is to pass a PHP variable to JavaScript. Below is a snippet from my MAIN PHP FILE: function ccss_show_tag_recipes() { //PHP code here } Next, here's t ...

What are the steps to integrate <br> in a JavaScript code?

I have recently started learning about web development and I'm facing a challenge with this implementation. var obj = [[{ name: "John", age: 30, city: "New York"}, { name: "Ken", age: 35, city: "New Orleans"}]]; ...

Divide a string into separate numbers using JavaScript

This snippet of code is designed to search the table #operations for all instances of <td> elements with the dynamic class ".fuel "+ACID: let k = 0; let ac_fuel = 0; parsed.data.forEach(arrayWithinData => { let ACID = parsed.data[k][0]; ...

Tips for transferring data and events between named views within Vue Router

I have a layout structured like this: .------------------------+----------------. | Current Tab Title | Controls | +------------------------+----------------+ | Tab1 Tab2 [Tab3] | +---------------------------------------- ...

I'm having trouble with populating data in Mongoose. Can anyone provide guidance on

I am currently working on a simple CRUD example for a larger open-source project. I'm trying to populate user data, but despite consulting documentation and forums, I haven't been able to resolve the issue that's causing trouble. The error ...

Locating the value of a data attribute from a distant parent div using jQuery

How can I access the closest div from an anchor tag that has a data-id attribute without using multiple parent() methods? Even though .parent().parent().parent() works, I am trying to find a better solution. <div class="panel panel-default" data-id="@ ...

Error: The name property is not defined and cannot be read in the Constructor.render function

Having trouble building a contact form and encountering an error when trying to access the values. I've checked for bugs in the console multiple times, but it seems like something is missing. Can anyone provide assistance? var fieldValues = { ...

Is there a requirement to download and set up any software in order to utilize Highchart?

I've been working on a project to create a program that displays highcharts, but all I'm getting is a blank page. Here's my code: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charse ...

Streaming data from MongoDB to a file using Node.js

Having recently delved into the world of javascript/node.js, I am attempting to accomplish a basic task: connect to MongoDB, convert the JSON response to CSV format, and then write it to a file. My current approach is outlined below: fs = require('fs ...

Is there a way to make my for loop search for the specific element id that I have clicked on?

When trying to display specific information from just one array, I'm facing an issue where the for loop is also iterating through other arrays and displaying their names. Is there a way to only show data from the intended array? const link = document. ...

How can one go about constructing abstract models using Prisma ORM?

Among my various prisma models, there are common fields such as audit fields like created_at and updated_at. model User { id Int @id @default(autoincrement()) created_at DateTime @default(now()) updated_at DateTime @updatedAt email ...