React上下文中的功能和重新渲染

时间:2018-09-29 20:49:14

标签: reactjs

关于新的React Context-api我有两个问题:

  1. React文档具有以下示例Updating context from a nested component。是否有某些特定原因会在构造函数中声明toggleTheme-function(而不是作为类方法)?

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    // State also contains the updater function so it will
    // be passed down into the context provider
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }

  render() {
    // The entire state is passed to the provider
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

function Content() {
  return (
    <div>
      <ThemeTogglerButton />
    </div>
  );
}

ReactDOM.render(<App />, document.root);

  1. 在许多示例中,Provider组件的状态为高阶组件的状态(就像上面的示例中一样)。这意味着,每次我要更新Context-value时,都需要更新上层组件的状态。这意味着高状态组件会随着状态的更新而重新呈现,这又意味着其所有子组件也会重新呈现。但是我想要的只是让消费者组件侦听该提供程序组件以重新呈现。现在基本上每次我更新Context-value时,整个应用都会重新渲染...我丢失了什么吗?

1 个答案:

答案 0 :(得分:1)

chrome.runtime.onMessage.addListener(function(message) { if (message.action == "init") { init(message.options.divider, message.options.delay, message.options.maxLosses); } if (message.action == "stop") { stop(); } }); var stop_flag; function init(divider, delay, maxLosses) { var $table = $('table.dice_table').last(); var lastBetNumber; var lastBetValue; var lastProfit; var losses = 0; stop_flag = false; loop_start(); function loop_start() { lastBetNumber = getLastBetNumber(); var betValue = (getCurrentBalance() / divider).toFixed(9); //var betValue = (getCurrentBalance() / divider); lastBetValue = betValue; $("input.bet").val(betValue); play(); setTimeout(loop, delay); } function loop() { if (stop_flag) return; waitForTableChange() .then(roll) .catch(loop_start); function roll() { //only if the last bet has changed \/ lastBetNumber = getLastBetNumber(); lastProfit = $table.children('tbody').children('tr').first().children('td').last().text()[0]; changeBet(); if (losses >= maxLosses) return; play(); setTimeout(loop, delay); } } function waitForTableChange() { return new Promise(function(resolve, reject) { var n = 0; attempt(); function attempt() { n++; if (n >= 100) { reject(); return; } if (getLastBetNumber() == lastBetNumber) { setTimeout(attempt, 100); return; } resolve(); } }); } function changeBet() { var newBetValue; if (lastProfit == "-") { losses++; newBetValue = lastBetValue * 2; } else { losses = 0; newBetValue = (getCurrentBalance() / divider).toFixed(9); } lastBetValue = newBetValue; $("input.bet").val(newBetValue); } function play() { $('input.clDicePlay').first()[0].click(); } function getLastBetNumber() { return $table.children('tbody').children('tr').first().children('td').first().text(); } function getCurrentBalance() { return $('.dice_select .chosen-single span').text().split('- ')[1].split(' ')[0]; } } function stop() { var audio = new Audio('play.mp3'); stop_flag = true; audio.play(); } 作为回调传递,应绑定到正确的toggleTheme。如果它是类原型方法,则将以任何方式在构造函数中需要this。参见this related question

the documentation所述,

  

作为提供商后代的所有消费者将在提供商的价值属性发生更改时重新呈现。从Provider到其后代的Consumer的传播不受shouldComponentUpdate方法的约束,因此即使祖先组件无法进行更新,也要对Consumer进行更新。

包含this.toggleTheme = this.toggleTheme.bind(this)Provider)的组件应重新渲染以提供新的App,而其后代则不应该。在此示例中,其直接子级(value)可以为Content,以防止在整个层次结构中不必要地重新渲染。对于会影响整个应用程序的上下文(如主题上下文),不会有明显的性能改进。