Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
249 views
in Technique[技术] by (71.8m points)

javascript - Changing the layout of a component depending on Redux state

I'm developing a course scheduling application in react, and I'm using it as a chance to learn redux. There's a browse menu (implemented as the Browse component) that I'm currently designing and it displays the list of schools in the university upon load. When a user clicks on one of the schools, it displays a list of subjects within that school. However, I would like the schools to be displayed as a grid (two columns), and I would like the subjects to be displayed as a list (one column). They also may presumably require different props to be fed to the Browse component.

How would I go about doing this? Currently, I have a Browse component and a BrowseReduxContainer component. The BrowseReduxContainer component uses connect(), mapStateToProps, and mapDispatchToProps from react-redux to populate the props of Browse. This works fine when I'm just displaying schools, but I'm not sure how to modify the layout of Browse depending upon the state. Should I be giving connect() different components depending on the state? Or should I implement logic within the Browse component to check the prop and display a grid/list accordingly? Or something else entirely?

actions.js

export function showSubjects(schoolId) {
  return {
    type: 'SHOW_SUBJECTS',
    schoolId
  };
}

browse.js

const initialState = {
    currentView: 'schools',
    schools: [{id: 'AAAA', name: 'aaaa'}, {id: 'BBBB', name: 'bbbb'}],
    subjects: [{id: 'CCC', name: 'ccc'}, {id: 'DDD', name: 'ddd'}]
};

function browse(state = initialState, action) {
  switch (action.type) {
    case 'SHOW_SUBJECTS':
      return {
        ...state,
        currentView: 'subjects'
      };
    default:
      return state;
  }
}

export default browse;

BrowseReduxContainer.jsx

import { connect } from 'react-redux';
import { showSubjects } from '../actions/actions';
import Browse from '../components/Browse.jsx';

function propsFilter(state) {
  switch (state.currentView) {
    case 'schools':
      return state.schools;
    case 'subjects':
      return state.subjects;
    default:
      throw new Error(`No such view: ${state.currentView}`);
  }
}

const mapStateToProps = (state) => ({
  schools: propsFilter(state)
});

const mapDispatchToProps = (dispatch) => ({
  showSubjects: (schoolId) => {
    dispatch(showSubjects(schoolId));
  }
});

const BrowseReduxContainer = connect(mapStateToProps, mapDispatchToProps)(Browse);

export default BrowseReduxContainer;

Browse.jsx

import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';

const Browse = (props) => (
  <div>
    {props.schools.map((school) => (
      <RaisedButton key={school.id} label={school.name} onClick={props.showSubjects(school.id)} />
    ))}
  </div>
);

export default Browse;

Other relevant files, if necessary, can be viewed here: https://github.com/Joonpark13/serif.nu/tree/feature/browse

UPDATE: My best guess at this point was to have different view components with their own appropriate props, perhaps called BrowseA and BrowseB and connect the appropriate one according to the state. I want to include this logic in mapDispatchToProps within BrowseReduxContainer, but then I realized the mapDispatchToProps function does not take state as a parameter. I'd love any suggestions!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

connect state on your Child components

Using connect on child components has the following advantages:

  • Your parent component need not bother about connecting all the props required by its children even though the parent itself is not using the prop.

  • Child components become more reusable, and easily maintainable.

  • Avoids passing down props blindly from parent to children. If the Child requires a considerable number of props, people don't want to explicitly pass only the required props, instead they tend to do this inside the parent: <Child {...this.props} />.

    Use connect and you know what your Component is getting.

  • You don't have to repeat propTypes definitions in parent and children.


Separate business logic from views:

Business logic is:

  • Any calculation based on data that came from the API or user input
  • Data normalization and formatting
  • Done in small increments or functions so that they are easily extendable, composable, and maintainable
  • Reuse the business logic functions in multiple views.

Views should:

  • Pull prepared data from state and/or business logic functions

  • Show or hide UI based on data

  • Simplify UI components so that they are small, reusable, and easily maintainable

  • Get props through connect from a business logic function.


What is a business logic function?

Business logic functions are small reusable functions that input data and output modified data. If they are small, they can be easily reused and modified. Business logic functions should be pure. Because business logic functions are often reused, they work best when memoized. In some languages these are called getters or selectors.

To streamline memoization, you may use reselect library. It’s a very simple as it only does two things: memoization and reusability. Take a look at the official API for more information on how it does that.

Advantages:

  • Business logic is in small functions that are easy to debug, enhance, maintain, read
  • Business logic functions are memoized so repeated calls are performant
  • Business logic is separated so it’s reusable across the app
  • The application is faster because main operations are highly optimized

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...