【问题标题】:Passing State as Props将状态作为道具传递
【发布时间】:2020-04-01 23:58:29
【问题描述】:

已编辑

所以我有一个计数器按钮组件,我在我的应用程序中呈现它。我的应用程序包含计数器的状态,但我如何将它作为道具传递给 Counter 组件?目前 Counter 有自己的状态,但我希望它使用 App 中的状态。

我还试图在一个单独的组件中创建一个通用计数器按钮,它将增加/减少重复的计数器按钮。但是我有同样的问题,我不确定如何正确地将应用程序的状态作为道具传递到这个通用按钮中。

万能计数器:

class UniversalCounter extends Component {
  constructor(props) {
    super(props);
    const allCounter = [Counter]
    this.state = allCounter;
  }

  incrementCount() { 
    this.setState(prevState => ({ allCounter: prevState.allCounter + 1 }));
  }

  decrementCount() {
    this.setState(prevState => ({ allCounter: prevState.allCounter - 1 }));
  }

  render() {
    let { allCounter } = this.state;

    return (
      <div>
        <h2>All Counters</h2>
        <button onClick={() => this.incrementCount(allCounter)}>increase all</button>
        <button onClick={() => this.decrementCount(allCounter)}>decrease all</button>
      </div>
    );
  }

计数器组件:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  incrementCount() {
     this.setState(prevState => ({ counter: prevState.counter+ 1 }));
  }

  decrementCount() {
    this.setState(prevState => ({ counter: prevState.counter- 1 }));
  }

  render() {
    let { counter} = this.state;

    return (
      <div>
        <h2>Count: {counter}</h2>
        <button onClick={() => this.incrementCount(counter)}>+</button>
        <button onClick={() => this.decrementCount(counter)}>-</button>
      </div>
    );
  }
}

应用:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  render() {
    let { counter } = this.state;

    return (
      <div className="App">
        <Counter/>
        <Counter/>
        <Counter/>
        <UniversalCounter />
      </div>
    );
  }
}

export default App;

【问题讨论】:

  • 移动 all 状态到父状态。你不想要多个事实来源。
  • 但如果通用按钮是唯一一个计数器处于状态的按钮,其他按钮将不起作用。
  • 你能展示一下它的外观吗?

标签: javascript reactjs counter


【解决方案1】:

将状态和处理程序放样到最近的共同祖先。 Counter 然后变成一个“哑”组件。

Lifting State Up

Counter.jsx

const Counter = ({ count, onIncrementClick, onDecrementClick }) => (
  <div>
    <h2>Count: {count}</h2>
    <button type="button" onClick={onIncrementClick}>
      +
    </button>
    <button type="button" onClick={onDecrementClick}>
      -
    </button>
  </div>
);

UniversalCounter.jsx

const UniversalCounter = () => {
  const [counters, setCounters] = useState([0, 0, 0]);

  const incrementCount = (index, c) => () =>
    setCounters(counts =>
      counts.map((count, i) => (index === i ? count + c : count))
    );

  const incrementCountAll = c => () =>
    setCounters(counts => counts.map((count, i) => count + c));

  return (
    <div>
      <h2>All Counters</h2>
      {counters.map((count, i) => (
        <Counter
          key={i}
          count={count}
          onIncrementClick={incrementCount(i, 1)}
          onDecrementClick={incrementCount(i, -1)}
        />
      ))}

      <button type="button" onClick={incrementCountAll(1)}>
        Increase All
      </button>
      <button type="button" onClick={incrementCountAll(-1)}>
        Decrease All
      </button>
    </div>
  );
};

如果(出于某种根本不是 DRY 的原因)想要单独渲染每个 Counter:

return (
  <div>
    <h2>All Counters</h2>

    <Counter
      count={counters[0]}
      onIncrementClick={incrementCount(0, 1)}
      onDecrementClick={incrementCount(0, -1)}
    />
    <Counter
      count={counters[1]}
      onIncrementClick={incrementCount(1, 1)}
      onDecrementClick={incrementCount(1, -1)}
    />
    <Counter
      count={counters[2]}
      onIncrementClick={incrementCount(2, 1)}
      onDecrementClick={incrementCount(2, -1)}
    />

    <button type="button" onClick={incrementCountAll(1)}>
      Increase All
    </button>
    <button type="button" onClick={incrementCountAll(-1)}>
      Decrease All
    </button>
  </div>
);

【讨论】:

  • 是否可以保留计数器组件“有状态”而不是像您说的“无状态”或“哑”?在我的 App.js 中,除了通用计数器之外,我还导入/调用了其他计数器,并希望保持这种状态。我会将我的应用添加到 OP。
  • 不是真的,您仍然希望每个计数器只有一个单一的事实来源,问题是每个计数器的更新功能是它们内部的,所以没有好的方法将它们暴露给树中组件处或之上的组件。将状态和行为放样到祖先的替代方法是使用全局状态(反应上下文,redux 等),但概念是相同的,每个“计数器”组件都连接到它可以的“状态片段”采取行动,一些“终极反击”可以对所有这些采取行动。例如,Redux 会通过调度的操作来处理这个问题。
  • 好的,我修改了我的代码,使其只有一个计数器组件,并在 App 中渲染 3 次,即状态所在的位置。将状态作为道具传递给计数器看起来如何?通用按钮可以在单独的组件中,状态作为道具传递吗?
  • @JabbatheHutt 添加回答如果你真的想看看它是如何做到的。
  • @JabbatheHutt 在您的沙箱中,CountincrementCountdecrementCount 作为道具,但您将onIncrementClickonDecrementClick 传递给App.js
猜你喜欢
  • 2018-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-19
  • 2019-11-30
  • 2017-04-30
  • 2019-02-20
  • 1970-01-01
相关资源
最近更新 更多