简体   繁体   中英

Set initial state from props in React componenet

I have such a component in which I set initial state from 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. I tried to use getDerivedStateFromProps(nextProps, prevState) React component initialize state from 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. How can I do that?

I would strongly discourage you from using getDerivedStateFromProps. This is why the reactjs blog has a post called "You Probably Don't Need Derived State"

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).

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.

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. the source of truth is the state.

(B) state (source of truth) => props => view // this is fine. the source of truth is the parent components state. (or alternatively, state would be the redux store - also fine)

(C) redux store (source of truth) => props => state => view // this is confusing. why aren't we just going store => props => view ?

(D) state (source of truth) => props => state => view // this is confusing. 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 . 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(){
 this.setState({
  selectedCar: this.props.data.selectedCar
 })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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