草庐IT

【react 全家桶】状态提升

追求~ 2023-05-18 原文

08 【状态提升】

文章目录

1.介绍

所谓 状态提升 就是将各个子组件的 公共state 提升到它们的父组件进行统一存储、处理(这就是所谓的”单一数据源“),负责setState的函数传到下边的子级组件,然后再将父组件处理后的数据或函数props到各子组件中。

那么如果子组件 要 修改父组件的state该怎么办呢?我们的做法就是 将父组件中负责setState的函数,以props的形式传给子组件,然后子组件在需要改变state时调用即可。

实现方式

实现方式是 利用最近的共同的父级组件中,用props的方式传过去到两个子组件,props中传的是一个setState的方法,通过子组件触发props传过去的方法,进而调用父级组件的setState的方法,改变了父级组件的state,调用父级组件的render方法,进而同时改变了两个子级组件的render。

这是 两个有关连的同级组件的传值,因为react的单项数据流,所以不在两个组件中进行传值,而是提升到 最近的共同的父级组件中,改变父级的state,进而影响了两个子级组件的render。

官网介绍

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

2.案例

先写一个温度输入组件:

class TemperatureInput extends React.Component {
    state = {
        temperature: ''
    };
    handleChange = (e) => {
        this.setState({
            temperature : e.target.value
        })
    };
    render() {
        return (
            <fieldset>
                <legend>输入{scaleNames[this.props.scale]}:</legend>
                <input type="number" value={this.state.temperature} onChange={this.handleChange}
            </fieldset>
        )
    }
}

这个组件就是一个普通的受控组件,有stateprops以及处理函数。

我们在写另一个组件:

class Calculator extends React.Component {
    render () {
        return (
            <div>
                <TemperatureInput scale='c'/>
                <TemperatureInput scale='f'/>
            </div>
        )
    }
}

这个组件现在没有什么存在的价值,我们仅仅是给两个温度输入组件提供一个父组件,以便我们进行后续的状态提升

现在我们看看网页的样子:

我们可以输入摄氏度和华氏度,但是我们现在想要让这两个温度保持一致,就是我们如果输入摄氏度,那么下面的华氏度可以自动算出来,如果我们输入华氏度,那么摄氏度就可以自动算出来。

那么我们按照现在这种结构的话,是非常难以实现的,因为我们知道这两个组件之间没有任何关系,它们之间是不知道对方的存在,所以我们需要把它们的状态进行提升,提升到它们的父组件当中。

那我们看看如何做修改,首先把子组件(温度输入组件)的状态(state)全部删除,看看是什么样子:

    class TemperatureInput extends React.Component {

        handleChange = (e) => {

        };

        render() {
            return (
                <fieldset>
                    <legend>输入{scaleNames[this.props.scale]}:</legend>
                    <input type="number" value={this.props.temperature} onChange={this.handleChange}/>
                </fieldset>
            )
        }
    }

可以看到所有与state有关的东西全部删掉了,然后inputvalue也变成了props,通过父组件传入。那么现在这个温度输入组件其实就是一个受控组件了,仔细回忆一下我们之前讲的受控组件,看看是不是这样意思?

我们通常会在受控组件发生改变的时候传入一个onChange函数来改变受控组件的状态,那么我们这里也是一样,我们通过给 温度输入组件 传入某个函数来让 温度输入组件 中的input发生变化的时候调用,当然这个函数我们可以随意命名,假如我们这里叫做onTemperatureChange函数,那么我们继续修改子组件:

    class TemperatureInput extends React.Component {

        handleChange = (e) => {
            this.props.onTemperatureChange(e.target.value);
        };

        render() {
            return (
                <fieldset>
                    <legend>输入{scaleNames[this.props.scale]}:</legend>
                    <input type="number" value={this.props.temperature} onChange={this.handleChange}/>
                </fieldset>
            )
        }
    }

好了,我们的子组件差不多就是这样了,当然我们可以省略那个handleChange函数,因为可以看到这个函数就是调用了一下那个props里的函数,所以我们完全把inputonChange这么写 <input type="number" value={this.props.temperature} onChange={this.props.onTemperatureChange}/>这么写的话注意onTemperatrueChange函数的参数是那个事件,而不是我这里写的e.target.value

再看看我们的父组件如何修改,我们首先补上state,以及子组件对应的onChange处理方法,以及子组件的值。写好之后大概是这个样子:

class Calculator extends React.Component {
    state = {
        celsius: '',
        fahrenheit: ''
    };

    onCelsiusChange = (value) => {
        this.setState({
            celsius: value,
            fahrenheit: tryConvert(value, toFahrenheit)
        });
    };

    onFahrenheitChange = (value) => {
        this.setState({
            celsius: tryConvert(value, toCelsius),
            fahrenheit: value
        });
    };

    render() {
        return (
            <div>
                <TemperatureInput scale='c' temperature={this.state.celsius}
                                  onTemperatureChange={this.onCelsiusChange}/>
                <TemperatureInput scale='f' temperature={this.state.fahrenheit}
                                  onTemperatureChange={this.onFahrenheitChange}/>
            </div>
        )
    }
}

这里我们省略的摄氏度与华氏度的转换函数,比较简单,大家自行搜索方法。

有关【react 全家桶】状态提升的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  3. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  4. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  5. ruby-on-rails - 为模型创建状态属性 - 2

    我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,

  6. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  7. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

  8. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  9. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

    我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

  10. ruby-on-rails - 状态机、模型验证和 RSpec - 2

    这是我当前的类定义和规范:classEvent:not_starteddoevent:game_starteddotransition:not_started=>:in_progressendevent:game_endeddotransition:in_progress=>:finalendevent:game_postponeddotransition[:not_started,:in_progress]=>:postponedendstate:not_started,:in_progress,:postponeddovalidate:end_time_before_finalen

随机推荐