React setState / Flux - 它是否总是触发重新渲染?

时间:2016-09-08 02:33:28

标签: reactjs react-native flux

我最近一直在玩React Native而且我已经达到了这样一个程度,我开始对这个状态更加正确地管理,作为开始在所有组件之间实现共享状态。

答案当然是Flux。在继续使用一些更先进的解决方案(例如Redux,Alt,MobX)之前,我认为我应该首先了解原始结构本身,借助一个小工具,即Flux调度程序。

import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';

import EventEmitter from 'EventEmitter';
import { Dispatcher } from 'flux';

class Store extends EventEmitter {
  list = [];

  actions = {
    add: title => dispatcher.dispatch({ type: 'add', payload: { title } })
  };

  handle = ({ type, payload }) => {
    switch(type) {
    case 'add': this.add(payload.title); break;
    }
  };

  add(title) {
    this.list.push(title);
    this.emit('change');
  }
}

const store = new Store(), dispatcher = new Dispatcher();

dispatcher.register(store.handle);

class App extends Component {
  state = { list: store.list };

  componentWillMount() {
    this.listener = store.addListener('change', () => this.setState({ list: store.list }));
  }

  componentDidMount() {
    setInterval(() => store.actions.add(new Date().getTime()), 1000);
  }

  componentWillUnmount() { this.listener.remove(); }

  render() {
    return (
      <View style={{ marginTop: 20 }}>
        <Text>{JSON.stringify(this.state.list)}</Text>
      </View>
    );
  }
}

AppRegistry.registerComponent('straightforwardFlux', () => App);

请注意,在视图层中,我们有{JSON.stringify(this.state.data)},当商店更新时,视图将重新呈现,因为它已链接到状态。

更改为{JSON.stringify(store.data)}时,视图也会重新渲染!这不应该发生,因为视图应该仅在直接影响视图的状态发生更改时更新,在这种情况下,视图中没有呈现任何状态。我在这里错过了什么吗?为什么我们会遇到这种行为?

这导致了另一个问题,每当状态发生变化时,是否会调用render()吗?即使它不影响视图层的外观?我已经调查了这个,我得到了两个不同的答案,一个是肯定的,componentShouldUpdate()默认返回true,这意味着需要在这里进行一些更改(如果是这样,怎么做?),另一个是根本不,它不会随每个setState()更新。

总的来说,这个实现是否正确?

1 个答案:

答案 0 :(得分:1)

根据documentation ...

  

除非在shouldComponentUpdate()中实现条件呈现逻辑,否则setState()将始终触发重新呈现。如果正在使用可变对象且无法在shouldComponentUpdate()中实现逻辑,则仅当新状态与先前状态不同时调用setState()将避免不必要的重新渲染。

tl; dr; React没有分析您的观点,以明确了解其所依赖的状态,由您自行优化shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState) {
  // check if your view's attributes changes
  let check1 = nextState.foo != this.state.foo
  let check2 = nextState.bar != this.state.bar

  // if return is true, the component will rerender
  return check1 || check2
}