简体   繁体   English

从 React 组件中的 props 设置初始状态

[英]Set initial state from props in React componenet

I have such a component in which I set initial state from props:我有这样一个组件,我在其中从 props 设置初始状态:

    class CarsModal extends PureComponent {
      constructor(props) {
        super(props);
        autoBind(this);

        const { data } = {} } = props;

        this.state = {
          selectedCar: data.category || '',
          cars: [],
          isSpam: data.spam,
          pick: data.pick,
          suitable: data.suitable,
          articles: false,
          show: false,
        };
        this.messageTimer = 0;
      }

      async componentDidMount() {
        const cars = await getCars();
        this.setState({
          cars,
        });
      }

      componentWillUnmount() {
        clearTimeout(this.messageTimer);
      }

      close() {

      }

      select(car) {
        this.setState({
          selectedCar: car,
        });
      }

      async save(scrapeRequest = false) {
        const { carId } = this.props;
        const {
          selectedCar,
          isSpam,
          pick,
          suitable,
          articles,
        } = this.state;

        await curateCar(storyId, {
          selectedCar,
          is_spam: isSpam,
          pick: pick,
          suitable: suitable,
          articles: articles,
          scrape: scrape,
        });

        if (!scrape) {
          this.setState({
            show: true,
          });
          clearTimeout(this.messageTimer);
          this.messageTimer = setTimeout(() => {
            this.setState({
              show: false,
            });
          }, 1500);
        }
      }

      scrape() {
        this.save(true);
      }

      toggle(key) {
        this.setState((state) => ({
          [key]: !state[key],
        }));
      }

      render() {
        const { show, curatorData } = this.props;
        const { author, cars, show } = this.state;

        return (
          <Modal
            show={show}
            onHide={this.handleClose}
            dialogClassName={cx('curate-modal')}
            centered
          >
            <ionClick={this.close} />
            <h3>Tools</h3>
            <div>
              <span>Auto:</span>
              <DropdownButton
                title={(
                  <>
                    {selectedAuthor}
                    <i />
                  </>
                )}

              >
                {cars.map((car) => (
                  <Dropdown.Item
                    key={author}
                    active={author === car}
                    onClick={() => this.select(author)}
                  >
                    {author}
                  </Dropdown.Item>
                ))}
              </DropdownButton>
            </div>
            {OPTIONS.map((option) => (
              <Option
                key={option.key}
                id={option.key}
                checked={this.state[option.key]}
                onChange={() => this.toggle(option.key)}
              >
                {option.content}
              </Option>
            ))}
            <div className={cx('update-info')}>
              <button
                type="button"
                onClick={() => this.save()}
              >
                Update
              </button>
              {showMessage && (
                <span>Updated</span>
              )}
            </div>
            <hr />
            <span
              className={cx('link')}
              onClick={this.scrape}
            >
              Scrape article
            </span>
            <a href='/'>Test 1</a>
            <a href='/'>Vtest 2</a>
          </Modal>
        );
      }
    }

    const mapDispatchToProps = (dispatch) => ({
      actions: bindActionCreators({ ...actions }, dispatch),
    });

    const mapStateToProps = (state) => ({
      userData: state.reducer.userData,
    });

but I know that setting initial state from props is antipattern.但我知道从 props 设置初始状态是反模式。 I tried to use getDerivedStateFromProps(nextProps, prevState) React component initialize state from props我尝试使用getDerivedStateFromProps(nextProps, prevState) React 组件从 props 初始化状态

But after that my state updates everytime and didn't change actually, is it updates with same props everytime.但是在那之后我的状态每次都会更新并且实际上并没有改变,它是否每次都使用相同的道具更新。 I need to set initial state only on INITIAL load.我只需要在INITIAL加载时设置初始状态。 How can I do that?我怎样才能做到这一点?

I would strongly discourage you from using getDerivedStateFromProps.我强烈建议您不要使用 getDerivedStateFromProps。 This is why the reactjs blog has a post called "You Probably Don't Need Derived State"这就是为什么 reactjs 博客有一篇名为“你可能不需要派生状态”的帖子

I think there's some general confusion about what exactly is wrong with setting initial state based on props (and what the point of props are).我认为对于基于 props 设置初始状态到底有什么问题(以及 props 的意义是什么)存在一些普遍的困惑。

The point of props is they provide an easy and consistent way to pass data around and react will automatically update when the view if those props change. props 的重点是它们提供了一种简单且一致的方式来传递数据,并且当这些 props 发生变化时,react 会自动更新视图。

The point of state is to provide a consistent way to store "stateful" information in your application (aka information that can change).状态点是提供一种一致的方式来在您的应用程序中存储“有状态”信息(也称为可以更改的信息)。

Let's map out a few examples:让我们绘制一些示例:

(A) state (source of truth) => view // this is fine. (A) state (source of truth) => view // 这很好。 the source of truth is the state.真相的来源是国家。

(B) state (source of truth) => props => view // this is fine. (B) state (source of truth) => props => view // 这很好。 the source of truth is the parent components state.真相的来源是父组件状态。 (or alternatively, state would be the redux store - also fine) (或者,状态将是 redux 商店 - 也很好)

(C) redux store (source of truth) => props => state => view // this is confusing. (C) redux store (source of truth) => props => state => view // 这令人困惑。 why aren't we just going store => props => view ?为什么我们不直接去store => props => view

(D) state (source of truth) => props => state => view // this is confusing. (D) state (source of truth) => props => state => view // 这令人困惑。 we now have the source of truth split between two separate states.我们现在有两个不同状态的真相来源。 However, this is not necessarily an anti-pattern in every case.然而,这并不一定在所有情况下都是反模式。

(E) state/store => props => state (after initial seed of data, this is the source of truth) => view

this is not an anti-pattern so long as you are only using the state from above as an initial seed of data.只要您仅使用上面的状态作为数据的初始种子,这就不是反模式 On subsequent renders, the flow of information in (E) is actually just state => view .在随后的渲染中,(E)中的信息流实际上只是state => view which is simple and unidirectional with a single source of truth.这是简单且单向的,具有单一的事实来源。

This post may be of help.这篇文章可能会有所帮助。

How about setting your state using your props, in componentDidMount?如何在 componentDidMount 中使用 props 设置状态?

componentDidMount(){
 this.setState({
  selectedCar: this.props.data.selectedCar
 })
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM