Можно ли разделить представление и логику для компонента в Redux / React?

Как показано в официальных документах redux -> https://redux.js.org/basics/usage-with-react, логика и предварительные настройки должны быть связаны вместе.

Вопрос в том, реально ли, что мы не можем разделить их, чтобы сделать наш код более понятным?

Например, какой-то компонент из официальных документов redux.js.org. Итак, логика и пресеты в нем вместе, и это выглядит не так хорошо и ясно:

import React from 'react'
import { connect } from 'react-redux'
import { addTodo } from '../actions'
 
let AddTodo = ({ dispatch }) => {
  let input
 
  return (
    <div>
      <form
        onSubmit = {e => {
          e.preventDefault()
          if (!input.value.trim()) {
            return
          }
          dispatch(addTodo(input.value))
          input.value = ''
        }}
      >
        <input
          ref = {node => {
            input = node
          }}
        />
        <button type = "submit">
          Add Todo
        </button>
      </form>
    </div>
  )
}
AddTodo = connect()(AddTodo)
 
export default AddTodo

P.S. Еще видел такой вопрос: Разделение презентационной и логической составляющих react / redux, это не то же самое.

UPD: I had separate the logic into onSubmit module and component presentation. But > for now I get an error - TypeError: Cannot call a class as a function :

/ * ПРЕЗЕНТАЦИЯ * /

import React from 'react';
import { connect } from 'react-redux';
import AddTodo from '../../Actions/AddTodo'
import addTodo from '../../Modules/handleClick'

class AddTodos extends React.Component{    
    componentDidMount() {
        console.info(addTodo()); // for test. Get "TypeError: Cannot call a class as a function"
    }

    render() {
        return (
            <form>
                <input type = "text" placeholder = "Your text" />
                <button type = "submit">Add todos</button>
            </form>
        );  
    }
}

export default AddTodos;

/ * ОТПРАВИТЬ МОДУЛЬ * /

import { connect } from 'react-redux';
import AddTodo from '../Actions/AddTodo'

let addTodo = ({ dispatch }) => {
    if (document.readyState === 'complete') {
        let form = document.querySelector('form');
        form.addEventListener('submit', handleClick);

        function handleClick(e) {
            e.preventDefault();

            let input = document.querySelector('input');    
            dispatch(AddTodo(input.value));

            input.value = '';
        }
    }
}

addTodo = connect()(addTodo);

export default addTodo;

Вы можете переместить обработчик onSubmit в отдельный метод класса,

MarkoCen 31.03.2018 15:41

Я разделил этот случай на модуль onSubmit и просто на презентацию. Но теперь я получаю ошибку TypeError: Cannot call a class as a function при вызове модуля onSubmit внутри component. UPD вопрос

Max Wolfen 31.03.2018 15:54

Вы используете создателя действий как функцию. addTodo - это не функция, это средство создания действия и должно использоваться с диспетчеризацией.

devserkan 31.03.2018 16:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
3
3
3 698
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Из той же документации, которую вы дали:

Sometimes it's hard to tell if some component should be a presentational component or a container. For example, sometimes form and function are really coupled together, such as in the case of this tiny component:

AddTodo is an input field with an “Add” button

Technically we could split it into two components but it might be too early at this stage. It's fine to mix presentation and logic in a component that is very small. As it grows, it will be more obvious how to split it, so we'll leave it mixed.

Итак, да, вы правы, лучше разделить наши презентационные и контейнерные компоненты, и это очень хорошо объяснено в документации, как вы заявили. Приведенный вами пример - просто исключение.

Вот как можно разделить компоненты:

AddTodo

import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { addTodo } from "../actions";
import AddTodoForm from "./AddTodoForm";

const AddTodo = ( props ) => {
    const handleAddTodo = todo => props.dispatch( addTodo( todo ) );

    return (
        <AddTodoForm addTodo = {handleAddTodo} />
    );
};

export default connect()( AddTodo );

AddTodoForm

import React from "react";

const AddTodoForm = ( props ) => {
    let input;

    const handleClick = () => {
        props.addTodo( input.value );
        input.value = "";
    };


    return (
        <div>
            <input
                ref = {( node ) => {
                    input = node;
                }}
            />
            <button
                onClick = {handleClick}
            >
    Add Todo
            </button>
        </div>
    );
};

export default AddTodoForm;

Я настоятельно рекомендую вам посмотреть видео Redux на Egghead от Дэна Абрамова (создателя Redux). Вы поймете логику Redux с нуля, посмотрев эти видео. Есть две части, смотрите обе части. Пока я изучал Redux, я смотрел их и писал все коды во время просмотра. После этого я создал репо: https://github.com/devserkan/react-with-idiomatic-redux

Вы можете клонировать это репо и играть как хотите.

Спасибо, но я не могу понять, как разделить презентацию и логику в данном случае. Может ты знаешь и сможешь это сделать? Я обновил вопрос и реализовал свою реализацию, но это не сработало ...

Max Wolfen 31.03.2018 16:00

В этом случае будет имя компонента AddTodoForm, включающее простую форму. У него будет функция handleSubmit, и он будет передавать входное значение реальной функции, которая будет выполнять отправку. Эта функция будет в нашем компоненте-контейнере и передаст эту функцию в наш AddTodoForm. Итак, для простой формы все становится сумасшедшим. Вот почему в документации говорится, что для этого этапа еще слишком рано. Позвольте мне сделать это, если у меня будет время.

devserkan 31.03.2018 16:30

Рассмотрите возможность использования шаблона контроллер / презентационный компонент medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7‌ d0

Anthony Manning-Franklin 31.03.2018 18:08

Спасибо, что указали на это @ AnthonyManning-Franklin. Я пересмотрел свой код и написал компоненты как функции.

devserkan 31.03.2018 23:51

Другие вопросы по теме