Запретить повторную визуализацию компонента, когда свойство не используется в функции рендеринга React Redux - PullRequest
0 голосов
/ 21 апреля 2020

Я борюсь с компонентом, который перерисовывает.
Я использую Redux для управления своими состояниями. В компоненте я использую свойство (isPlaying: bool) из моего состояния с mapStateToProps в некоторых методах моего компонента (класса) , за исключением функции рендеринга , и я использую некоторые создатели действий отправляют изменения для isPlaying . Между прочим, я использую isPlaying в другом дочернем компоненте ( Musi c Player ), используя connect (реаги-редукс).
Это то, что я ' Я ожидаю :
Когда isPlaying изменится, родительский компонент не выполнит повторную визуализацию, а Musi c Bar выполнит повторную визуализацию, и я продолжу использовать isPlaying в методах моего родительского компонента.
В чем проблема :
Родительский компонент перерисовывается, даже если я не использую isPlaying в метод рендеринга.
Извините, если я вас смутил во время чтения. Я не являюсь носителем английского языка sh.
Заранее спасибо.

Редактировать: Добавить упрощенную версию кода.
Мой инициал состояние:

export default {
// Some Irrelevant Properties
...

playlist: {
    isPlaying: false,
    playingTrack: null,
    nextTrack: null,
    prevTrack: null,
    views: null,
    totalListens: null,
    tracks: []
}

};

Вот мой родительский компонент. (Приложение. js)

import ...
class App extends React.Component {
constructor(props) {
        super(props)
        this.state = {
            widgets: [],
            links: [],
            clickedTrack: null
        }

        this.musicBarRef = React.createRef()
        this._isMounted = false;

        // Binding this to the methods used in this Component
        ...

    }
    // All my methods here
    // Example of one function 
    playTrack() {
        let {isPlaying} = this.props
        if (isPlaying) {
            // Pause
        } else {
            // Play
        }
    }

    render() {
        <>
            // Some irrelevant components (don't use isPlaying)
            <TracksPlaylist tracks={this.props.tracks} and some the methods created above />
            <MusicBar ref={this.musicBarRef} and some methods created above />

            // Example of one irrelevant component that re-renders
            <Footer />
        </>
    }
}

const mapStateToProps = (state) => {
    return {
        isPlaying: state.playlist.isPlaying,
        selectedTrack: state.playlist.playingTrack,
        nextTrack: state.playlist.nextTrack,
        prevTrack: state.playlist.prevTrack,
        tracks: state.playlist.tracks,
    }
}

const mapDispatchToProps = {
    setPlaying: startPlaying, // Set isPlaying: true
    setNotPlaying: stopPlaying, // Set isPlaying: false
    // Some Irrelevent Action Creators
    ...
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

Вот мой редуктор

import * as types from "../actions/actionTypes";
import initialState from "./initialState";

export default function musicPlayerReducer(state = initialState.playlist, action) {
    switch (action.type) {
        // Some irrelevant cases
        ...

        case types.STOP_PLAYING:
            return {...state, isPlaying: false}
        case types.START_PLAYING:
            return {...state, isPlaying: true}
        case types.NEXT_TRACK_FOUND:
            return {...state, nextTrack: action.track}
        case types.PREV_TRACK_FOUND:
            return {...state, prevTrack: action.track}
        case types.CURRENT_TRACK_FOUND:
            return {...state, playingTrack: action.track}
        default:
            return state
    }
}

TracksPlaylist, упомянутый в приложении. js

import ...

class TracksPlaylist extends React.Component {

    constructor(props) {
        super(props)
    }

    render() {
        let {tracks, onPlayClick ... and other methods from App.js} = this.props
        return (
            <div className="songs">
                {
                    Object.values(tracks).length > 0 ?
                        Object.values(tracks).map((item, index) => {
                            return <Track onPlayClick={onPlayClick} key={index} item={item} />
                        }) :
                        ''
                }
            </div>
        )
    }
}
const mapStateToProps = (state) => {
    return {
        tracks: state.playlist.tracks,
    }
}

const mapDispatchToProps = {
    setPlaying: startPlaying,
    setNotPlaying: stopPlaying,

    // Some irrelevant functions
    ...
}

export default connect(mapStateToProps, mapDispatchToProps)(Tracks)

Компонент Track

import ...

class Track extends React.Component {
    constructor(props) {
        super(props)
    }

    hasInteraction(interactionType, trackId) {
        return false
    }


    render() {
        let {onPlayClick, item} = this.props
        return (
            <div key={item.track_id} className="track" id={item.track_id} data-category={item.category_name}>
                    // A lot of irrelevant JSX :)
                    <TrackAction onPlayClick={onPlayClick} item={item} />
                </div>
            </div>
        )
    }

}

export default Track

Вот TrackAction (он использует isPlaying):

import ...

function TrackAction({item, isPlaying, playingTrack, onPlayClick}) {
    return (
        <div className="status action play-track" onClick={onPlayClick}>
            <i id={item.track_id} className={isPlaying && playingTrack.track_id === item.track_id ? 'fas fa-pause' : 'fas fa-play'} />
        </div>
    )
}

const mapStateToProps = (state) => {
    return {
        isPlaying: state.playlist.isPlaying,
        playingTrack: state.playlist.playingTrack
    }
}

export default connect(mapStateToProps)(TrackAction)

Я использовал TrackAction, чтобы сделать только этот компонент для повторного рендеринга, потому что isPlaying меняется, и он зарегистрирован в этом компоненте и используется в его визуализации ().
Еще раз спасибо.

1 Ответ

0 голосов
/ 21 апреля 2020

Несмотря на то, что вы не используете isPlaying внутри render метода, вы все еще подписываетесь на изменение из-за привязки mapStateToProps.

Всякий раз, когда меняется State || Props, React просто повторяет рендеринг новый обновленный state || props с просто поверхностным сравнением.

И это причина, по которой ваш родитель перерисовывается.

Одним из возможных решений является переопределение shouldcomponentupdate

https://reactjs.org/docs/react-component.html#shouldcomponentupdate

Используйте shouldComponentUpdate (), чтобы сообщить React, если на выход компонента не влияет текущее изменение состояния или подпорок. Поведение по умолчанию заключается в повторной визуализации при каждом изменении состояния.

По умолчанию установлено значение true. Если вы переопределите и вернете false, UNSAFE_componentWillUpdate (), render () и componentDidUpdate () не будут вызваны.

Пример кода:

shouldComponentUpdate(nextProps, nextState) {
  return <enter_your_condition_to_be_true>; // else false
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...