最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ReactJs: change state in response to state change - Stack Overflow

programmeradmin3浏览0评论

I've got a React ponent with an input, and an optional "advanced input":

[ basic ]
Hide Advanced...
[ advanced ]

The advanced on the bottom goes away if you click "Hide Advanced", which changes to "Show Advanced". That's straightforward and working fine, there's a showAdvanced key in the state that controls the text and whether the advanced input is rendered.

External JS code, however, might change the value of advanced, in which case I want to show the [advanced] input if it's currently hidden and the value is different than the default. The user should be able to click "Hide Advanced" to close it again, however.

So, someone external calls cmp.setState({advanced: "20"}), and I want to then show advanced; The most straightforward thing to do would just be to update showAdvanced in my state. However, there doesn't seem to be a way to update some state in response to other state changes in React. I can think of a number of workarounds with slightly different behavior, but I really want to have this specific behavior.

Should I move showAdvanced to props, would that make sense? Can you change props in response to state changes? Thanks.

I've got a React ponent with an input, and an optional "advanced input":

[ basic ]
Hide Advanced...
[ advanced ]

The advanced on the bottom goes away if you click "Hide Advanced", which changes to "Show Advanced". That's straightforward and working fine, there's a showAdvanced key in the state that controls the text and whether the advanced input is rendered.

External JS code, however, might change the value of advanced, in which case I want to show the [advanced] input if it's currently hidden and the value is different than the default. The user should be able to click "Hide Advanced" to close it again, however.

So, someone external calls cmp.setState({advanced: "20"}), and I want to then show advanced; The most straightforward thing to do would just be to update showAdvanced in my state. However, there doesn't seem to be a way to update some state in response to other state changes in React. I can think of a number of workarounds with slightly different behavior, but I really want to have this specific behavior.

Should I move showAdvanced to props, would that make sense? Can you change props in response to state changes? Thanks.

Share Improve this question asked Sep 12, 2014 at 0:09 EmosesEmoses 3651 gold badge4 silver badges8 bronze badges 3
  • Setting one state depending on another state does sound like an anti-pattern. Why don’t you just check the advanced state in the render method? – David Hellsing Commented Sep 12, 2014 at 11:32
  • Do you have a jsfiddle? If I understand correctly, you want to control the visibility of an element from inside your ponent, but also from outside right? So I would just use a prop, and have a if condition to check whether or not you should display it. – Jeremy D Commented Sep 13, 2014 at 11:05
  • @DavidHellsing I have the same question and don't consider it an antipattern: Consider the case if the state change in response to other state change requires retrieving data from network or plex calculations. Retrieving it every time when render runs would be an antipattern on the contrary! – porton Commented Dec 22, 2020 at 8:20
Add a ment  | 

2 Answers 2

Reset to default 9

Okay first up, you mention that a third party outside of your ponent might call cmp.setState()? This is a huge react no-no. A ponent should only ever call it's own setState function - nothing outside should access it.

Also another thing to remember is that if you're trying change state again in response to a state change - that means you're doing something wrong.

When you build things in this way it makes your problem much harder than it needs to be. The reason being that if you accept that nothing external can set the state of your ponent - then basically the only option you have is to allow external things to update your ponent's props - and then react to them inside your ponent. This simplifies the problem.

So for example you should look at having whatever external things that used to be calling cmp.setState() instead call React.renderComponent on your ponent again, giving a new prop or prop value, such as showAdvanced set to true. Your ponent can then react to this in ponentWillReceiveProps and set it's state accordingly. Here's an example bit of code:

var MyComponent = React.createClass({
    getInitialState: function() {
        return {
            showAdvanced: this.props.showAdvanced || false
        }
    },
    ponentWillReceiveProps: function(nextProps) {
        if (typeof nextProps.showAdvanced === 'boolean') {
            this.setState({
                showAdvanced: nextProps.showAdvanced
            })
        }
    },
    toggleAdvancedClickHandler: function(e) {
        this.setState({
            showAdvanced: !this.state.showAdvanced
        })
    },
    render: function() {
        return (
            <div>
                <div>Basic stuff</div>
                <div>
                    <button onClick={this.toggleAdvancedClickHandler}>
                        {(this.state.showAdvanced ? 'Hide' : 'Show') + ' Advanced'}
                    </button>
                </div>
                <div style={{display: this.state.showAdvanced ? 'block' : 'none'}}>
                    Advanced Stuff
                </div>
            </div>
        );
    }
});

So the first time you call React.renderComponent(MyComponent({}), elem) the ponent will mount and the advanced div will be hidden. If you click on the button inside the ponent, it will toggle and show. If you need to force the ponent to show the advanced div from outside the ponent simply call render again like so: React.renderComponent(MyComponent({showAdvanced: true}), elem) and it will show it, regardless of internal state. Likewise if you wanted to hide it from outside, simply call it with showAdvanced: false.

Added bonus to the above code example is that calling setState inside of ponentWillReceiveProps does not cause another render cycle, as it catches and changes the state BEFORE render is called. Have a look at the docs here for more info: http://facebook.github.io/react/docs/ponent-specs.html#updating-ponentwillreceiveprops

Don't forget that calling renderComponent again on an already mounted ponent doesn't mount it again, it just tells react to update the ponent's props and react will then make the changes, run the lifecycle and render functions of the ponent and do it's dom diffing magic.

Revised answer in ment below.


My initial wrong answer:

The lifecycle function ponentWillUpdate will be ran when new state or props are received. You can find documentation on it here: http://facebook.github.io/react/docs/ponent-specs.html#updating-ponentwillupdate

If, when the external setState is called, you then set showAdvanced to true in ponentWillUpdate, you should get the desired result.

EDIT: Another option would be to have the external call to setState include showAdvanced: true in its new state.

发布评论

评论列表(0)

  1. 暂无评论