React设计模式:深入理解React&Redux原理套路

原文地址

本文从属于笔者的React入门与最佳实践系列,推荐阅读GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean

Communication

React组件一个很大的特性在于其拥有自己完整的生命周期,因此我们可以将React组件视作可自运行的小型系统,它拥有自己的内部状态、输入与输出。

Input

对于React组件而言,其输入的来源就是Props,我们会用如下方式向某个React组件传入数据:


// Title.jsx
class Title extends React.Component {
  render() {
    return 

{ this.props.text }

; } }; Title.propTypes = { text: React.PropTypes.string }; Title.defaultProps = { text: 'Hello world' }; // App.jsx class App extends React.Component { render() { return ; } };</code></pre> <p><code>text</code>是<code>Text</code>组件自己的输入域,父组件<code>App</code>在使用子组件<code>Title</code>时候应该提供<code>text</code>属性值。除了标准的属性名之外,我们还会用到如下两个设置:</p> <ul> <li><p>propTypes:用于定义Props的类型,这有助于追踪运行时误设置的Prop值。</p></li> <li><p>defaultProps:定义Props的默认值,这个在开发时很有帮助</p></li> </ul> <p>Props中还有一个特殊的属性<code>props.children</code>可以允许我们使用子组件:</p> <pre><code> class Title extends React.Component { render() { return ( <h1> { this.props.text } { this.props.children } </h1> ); } }; class App extends React.Component { render() { return ( <Title text='Hello React'> <span>community</span> ); } };

注意,如果我们不主动在Title组件的render函数中设置{this.props.children},那么span标签是不会被渲染出来的。除了Props之外,另一个隐性的组件的输入即是context,整个React组件树会拥有一个context对象,它可以被树中挂载的每个组件所访问到,关于此部分更多的内容请参考依赖注入这一章节。

Output

组件最明显的输出就是渲染后的HTML文本,即是React组件渲染结果的可视化展示。当然,部分包含了逻辑的组件也可能发送或者触发某些Action或者Event。


class Title extends React.Component {
  render() {
    return (
      

); } }; class App extends React.Component { render() { return ; } logoClicked() { console.log('logo clicked'); } };</code></pre> <p>在<code>App</code>组件中我们向<code>Title</code>组件传入了可以从<code>Title</code>调用的回调函数,在<code>logoClicked</code>函数中我们可以设置或者修改需要传回父组件的数据。需要注意的是,React并没有提供可以访问子组件状态的API,换言之,我们不能使用<code>this.props.children[0].state</code>或者类似的方法。正确的从子组件中获取数据的方法应该是在Props中传入回调函数,而这种隔离也有助于我们定义更加清晰的API并且促进了所谓单向数据流。</p> <h1>Composition</h1> <p>React最大的特性之一即是其强大的组件的可组合性,实际上除了React之外,笔者并不知道还有哪个框架能够提供如此简单易用的方式来创建与组合各式各样的组件。本章我们会一起讨论些常用的组合技巧,我们以一个简单的例子来进行讲解。假设在我们的应用中有一个页首栏目,并且其中放置了导航栏。我们创建了三个独立的React组件:<code>App</code>,<code>Header</code>以及<code>Navigation</code>。将这三个组件依次嵌套组合,可以得到以下的代码:</p> <pre><code> <App> <Header> <Navigation> ... </Navigation> </Header> </App></code></pre> <p>而在JSX中组合这些组件的方式就是在需要的时候引用它们:</p> <pre><code> // app.jsx import Header from './Header.jsx'; export default class App extends React.Component { render() { return <Header />; } } // Header.jsx import Navigation from './Navigation.jsx'; export default class Header extends React.Component { render() { return <header><Navigation /></header>; } } // Navigation.jsx export default class Navigation extends React.Component { render() { return (<nav> ... </nav>); } }</code></pre> <p>不过这种方式却可能存在以下的问题:</p> <ul> <li><p>我们将<code>App</code>当做各个组件间的连接线,也是整个应用的入口,因此在<code>App</code>中进行各个独立组件的组合是个不错的方法。不过<code>Header</code>元素中可能包含像图标、搜索栏或者Slogan这样的元素。而如果我们需要另一个不包含<code>Navigation</code>功能的<code>Header</code>组件时,像上面这种直接将<code>Navigation</code>组件硬编码进入<code>Header</code>的方式就会难于修改。</p></li> <li><p>这种硬编码的方式会难以测试,如果我们在<code>Header</code>中加入一些自定义的业务逻辑代码,那么在测试的时候当我们要创建<code>Header</code>实例时,因为其依赖于其他组件而导致了这种依赖层次过深(这里不包含Shallow Rendering这种仅渲染父组件而不渲染嵌套的子组件方式)。</p></li> </ul> <h2>使用React的<code>children</code>API</h2> <p>React为我们提供了<code>this.props.children</code>来允许父组件访问其子组件,这种方式有助于保证我们的<code>Header</code>独立并且不需要与其他组件解耦合。</p> <pre><code> // App.jsx export default class App extends React.Component { render() { return ( <Header> <Navigation /> </Header> ); } } // Header.jsx export default class Header extends React.Component { render() { return <header>{ this.props.children }</header>; } };</code></pre> <p>这种方式也有助于测试,我们可以选择输入空白的<code>div</code>元素,从而将要测试的目标元素隔离开来而专注于我们需要测试的部分。</p> <h2>将子组件以属性方式传入</h2> <p>React组件可以接受Props作为输入,我们也可以选择将需要封装的组件以Props方式传入:</p> <pre><code> // App.jsx class App extends React.Component { render() { var title = <h1>Hello there!</h1>; return ( <Header title={ title }> <Navigation /> </Header> ); } }; // Header.jsx export default class Header extends React.Component { render() { return ( <header> { this.props.title } <hr /> { this.props.children } </header> ); } };</code></pre> <p>这种方式在我们需要对传入的待组合组件进行一些修正时非常适用。</p> <h1>Higher-order components</h1> <p>Higher-Order Components模式看上去非常类似于装饰器模式,它会用于包裹某个组件然后为其添加一些新的功能。这里展示一个简单的用于构造Higher-Order Component的函数:</p> <pre><code> var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} /> ) } }; export default enhanceComponent;</code></pre> <p>通常情况下我们会构建一个工厂函数,接收原始的组件然后返回一个所谓的增强或者包裹后的版本,譬如:</p> <pre><code> var OriginalComponent = () => <p>Hello world.</p>; class App extends React.Component { render() { return React.createElement(enhanceComponent(OriginalComponent)); } };</code></pre> <p>一般来说,高阶组件的首要工作就是渲染原始的组件,我们经常也会将Props与State传递进去,将这两个属性传递进去会有助于我们建立一个数据代理。HOC模式允许我们控制组件的输入,即将需要传入的数据以Props传递进去。譬如我们需要为原始组件添加一些配置:</p> <pre><code> var config = require('path/to/configuration'); var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} title={ config.appTitle } /> ) } };</code></pre> <p>这里对于<code>configuration</code>的细节实现会被隐藏到高阶组件中,原始组件只需要了解从Props中获取到<code>title</code>变量然后渲染到界面上。原始组件并不会关心变量存于何地,从何而来,这种模式最大的优势在于我们能够以独立的模式对该组件进行测试,并且可以非常方便地对该组件进行Mocking。在HOC模式下我们的原始组件会变成这样子:</p> <pre><code> var OriginalComponent = (props) => <p>{ props.title }</p>;</code></pre> <h1>Dependency injection</h1> <p>我们写的大部分组件与模块都会包含一些依赖,合适的依赖管理有助于创建良好可维护的项目结构。而所谓的依赖注入技术正是解决这个问题的常用技巧,无论是在Java还是其他应用程序中,依赖注入都受到了广泛的使用。而React中对于依赖注入的需要也是显而易见的,让我们假设有如下的应用树结构:</p> <pre><code> // Title.jsx export default function Title(props) { return <h1>{ props.title }</h1>; } // Header.jsx import Title from './Title.jsx'; export default function Header() { return ( <header> <Title /> </header> ); } // App.jsx import Header from './Header.jsx'; class App extends React.Component { constructor(props) { super(props); this.state = { title: 'React in patterns' }; } render() { return <Header />; } };</code></pre> <p><code>title</code>这个变量的值是在<code>App</code>组件中被定义好的,我们需要将其传入到<code>Title</code>组件中。最直接的方法就是将其从<code>App</code>组件传入到<code>Header</code>组件,然后再由<code>Header</code>组件传入到<code>Title</code>组件中。这种方法在这里描述的简单的仅有三个组件的应用中还是非常清晰可维护的,不过随着项目功能与复杂度的增加,这种层次化的传值方式会导致很多的组件要去考虑它们并不需要的属性。在上文所讲的HOC模式中我们已经使用了数据注入的方式,这里我们使用同样的技术来注入<code>title</code>变量:</p> <pre><code> // enhance.jsx var title = 'React in patterns'; var enhanceComponent = (Component) => class Enhance extends React.Component { render() { return ( <Component {...this.state} {...this.props} title={ title } /> ) } }; export default enhanceComponent; // Header.jsx import enhance from './enhance.jsx'; import Title from './Title.jsx'; var EnhancedTitle = enhance(Title); export default function Header() { return ( <header> <EnhancedTitle /> </header> ); }</code></pre> <p>在上文这种HOC模式中,<code>title</code>变量被包含在了一个隐藏的中间层中,我们将其作为Props值传入到原始的<code>Title</code>变量中并且得到一个新的组件。这种方式思想是不错,不过还是只解决了部分问题。现在我们可以不去显式地将<code>title</code>变量传递到<code>Title</code>组件中即可以达到同样的<code>enhance.jsx</code>效果。</p> <p>React为我们提供了<code>context</code>的概念,<code>context</code>是贯穿于整个React组件树允许每个组件访问的对象。有点像所谓的Event Bus,一个简单的例子如下所示:</p> <pre><code> // a place where we'll define the context var context = { title: 'React in patterns' }; class App extends React.Component { getChildContext() { return context; } ... }; App.childContextTypes = { title: React.PropTypes.string }; // a place where we need data class Inject extends React.Component { render() { var title = this.context.title; ... } } Inject.contextTypes = { title: React.PropTypes.string };</code></pre> <p>注意,我们要使用context对象必须要通过<code>childContextTypes</code>与<code>contextTypes</code>指明其构成。如果在<code>context</code>对象中未指明这些那么<code>context</code>会被设置为空,这可能会添加些额外的代码。因此我们最好不要将<code>context</code>当做一个简单的object对象而为其设置一些封装方法:</p> <pre><code> // dependencies.js export default { data: {}, get(key) { return this.data[key]; }, register(key, value) { this.data[key] = value; } }</code></pre> <p>这样,我们的<code>App</code>组件会被改造成这样子:</p> <pre><code> import dependencies from './dependencies'; dependencies.register('title', 'React in patterns'); class App extends React.Component { getChildContext() { return dependencies; } render() { return <Header />; } }; App.childContextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func };</code></pre> <p>而在<code>Title</code>组件中,我们需要进行如下设置:</p> <pre><code> // Title.jsx export default class Title extends React.Component { render() { return <h1>{ this.context.get('title') }</h1> } } Title.contextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func };</code></pre> <p>当然我们不希望在每次要使用<code>contextTypes</code>的时候都需要显式地声明一下,我们可以将这些声明细节包含在一个高阶组件中。</p> <pre><code> // Title.jsx import wire from './wire'; function Title(props) { return <h1>{ props.title }</h1>; } export default wire(Title, ['title'], function resolve(title) { return { title }; });</code></pre> <p>这里的<code>wire</code>函数的第一个参数是React组件对象,第二个参数是一系列需要注入的依赖值,注意,这些依赖值务必已经调用过<code>register</code>函数。最后一个参数则是所谓的映射函数,它接收存储在<code>context</code>中的某个原始值然后返回React Props中需要的值。因为在这个例子里<code>context</code>中存储的值与<code>Title</code>组件中需要的值都是<code>title</code>变量,因此我们直接返回即可。不过在真实的应用中可能是一个数据集合、配置等等。</p> <pre><code> export default function wire(Component, dependencies, mapper) { class Inject extends React.Component { render() { var resolved = dependencies.map(this.context.get.bind(this.context)); var props = mapper(...resolved); return React.createElement(Component, props); } } Inject.contextTypes = { data: React.PropTypes.object, get: React.PropTypes.func, register: React.PropTypes.func }; return Inject; };</code></pre> <p>这里的Inject就是某个可以访问<code>context</code>的高阶组件,而<code>mapper</code>就是用于接收<code>context</code>中的数据并将其转化为组件所需要的Props的函数。实际上现在大部分的依赖注入的解决方案都是基于<code>context</code>,我觉得了解这种方式的底层原理还是很有意义的。譬如现在流行的<code>Redux</code>,其核心的<code>connect</code>函数与<code>Provider</code>组件都是基于<code>context</code>。</p> <h1>One direction data flow</h1> <p>单向数据流是React中主要的数据驱动模式,其核心概念在于组件并不会修改它们接收到的数据,它们只是负责接收新的数据而后重新渲染到界面上或者发出某些Action以触发某些专门的业务代码来修改数据存储中的数据。我们先设置一个包含一个按钮的<code>Switcher</code>组件,当我们点击该按钮时会触发某个<code>flag</code>变量的改变:</p> <pre><code> class Switcher extends React.Component { constructor(props) { super(props); this.state = { flag: false }; this._onButtonClick = e => this.setState({ flag: !this.state.flag }); } render() { return ( <button onClick={ this._onButtonClick }> { this.state.flag ? 'lights on' : 'lights off' } </button> ); } }; // ... and we render it class App extends React.Component { render() { return <Switcher />; } };</code></pre> <p>此时我们将所有的数据放置到组件内,换言之,<code>Switcher</code>是唯一的包含我们<code>flag</code>变量的地方,我们来尝试下将这些数据托管于专门的Store中:</p> <pre><code> var Store = { _flag: false, set: function(value) { this._flag = value; }, get: function() { return this._flag; } }; class Switcher extends React.Component { constructor(props) { super(props); this.state = { flag: false }; this._onButtonClick = e => { this.setState({ flag: !this.state.flag }, () => { this.props.onChange(this.state.flag); }); } } render() { return ( <button onClick={ this._onButtonClick }> { this.state.flag ? 'lights on' : 'lights off' } </button> ); } }; class App extends React.Component { render() { return <Switcher onChange={ Store.set.bind(Store) } />; } };</code></pre> <p>这里的<code>Store</code>对象是一个简单的单例对象,可以帮助我们设置与获取<code>_flag</code>属性值。而通过将<code>getter</code>函数传递到组件内,可以允许我们在<code>Store</code>外部修改这些变量,此时我们的应用工作流大概是这样的:</p> <pre><code> User's input | Switcher -------> Store</code></pre> <p>假设我们已经将<code>flag</code>值保存到某个后端服务中,我们需要为该组件设置一个合适的初始状态。此时就会存在一个问题在于同一份数据保存在了两个地方,对于UI与<code>Store</code>分别保存了各自独立的关于<code>flag</code>的数据状态,我们等于在<code>Store</code>与<code>Switcher</code>之间建立了双向的数据流:<code>Store ---> Switcher</code>与<code>Switcher ---> Store</code></p> <pre><code> // ... in App component <Switcher value={ Store.get() } onChange={ Store.set.bind(Store) } /> // ... in Switcher component constructor(props) { super(props); this.state = { flag: this.props.value }; ...</code></pre> <p>此时我们的数据流向变成了:</p> <pre><code> User's input | Switcher <-------> Store ^ | | | | | | v Service communicating with our backend</code></pre> <p>在这种双向数据流下,如果我们在外部改变了<code>Store</code>中的状态之后,我们需要将改变之后的最新值更新到<code>Switcher</code>中,这样也在无形之间增加了应用的复杂度。而单向数据流则是解决了这个问题,它强制在全局只保留一个状态存储,通常是存放在Store中。在单向数据流下,我们需要添加一些订阅Store中状态改变的响应函数:</p> <pre><code> var Store = { _handlers: [], _flag: '', onChange: function(handler) { this._handlers.push(handler); }, set: function(value) { this._flag = value; this._handlers.forEach(handler => handler()) }, get: function() { return this._flag; } };</code></pre> <p>然后我们在<code>App</code>组件中设置了钩子函数,这样每次<code>Store</code>改变其值的时候我们都会强制重新渲染:</p> <pre><code> class App extends React.Component { constructor(props) { super(props); Store.onChange(this.forceUpdate.bind(this)); } render() { return ( <div> <Switcher value={ Store.get() } onChange={ Store.set.bind(Store) } /> </div> ); } };</code></pre> <p>注意,这里使用的<code>forceUpdate</code>并不是一个推荐的用法,我们通常会使用HOC模式来进行重渲染,这里使用<code>forceUpdate</code>只是用于演示说明。在基于上述的改造,我们就不需要在组件中继续保留内部状态:</p> <pre><code> class Switcher extends React.Component { constructor(props) { super(props); this._onButtonClick = e => { this.props.onChange(!this.props.value); } } render() { return ( <button onClick={ this._onButtonClick }> { this.props.value ? 'lights on' : 'lights off' } </button> ); } };</code></pre> <p>这种模式的优势在于会将我们的组件改造为简单的<code>Store</code>中数据的呈现,此时才是真正无状态的View。我们可以以完全声明式的方式来编写组件,而将应用中复杂的业务逻辑放置到单独的地方。此时我们应用程序的流图变成了:</p> <pre><code> Service communicating with our backend ^ | v Store <----- | | v | Switcher ----> ^ | | User input</code></pre> <p>在这种单向数据流中我们不再需要同步系统中的多个部分,这种单向数据流的概念并不仅仅适用于基于React的应用。</p> <h1>Flux</h1> <blockquote> <p>关于Flux的简单了解可以参考笔者的GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean</p> </blockquote> <p>Flux是用于构建用户交互界面的架构模式,最早由Facebook在f8大会上提出,自此之后,很多的公司开始尝试这种概念并且貌似这是个很不错的构建前端应用的模式。Flux经常和React一起搭配使用,笔者本身在日常的工作中也是使用React+Flux的搭配,给自己带来了很大的遍历。</p> <p><span class="img-wrap"></span></p> <p>Flux中最主要的角色为Dispatcher,它是整个系统中所有的Events的中转站。Dispatcher负责接收我们称之为Actions的消息通知并且将其转发给所有的Stores。每个Store实例本身来决定是否对该Action感兴趣并且是否相应地改变其内部的状态。当我们将Flux与熟知的MVC相比较,你就会发现Store在某些意义上很类似于Model,二者都是用于存放状态与状态中的改变。而在系统中,除了View层的用户交互可能触发Actions之外,其他的类似于Service层也可能触发Actions,譬如在某个HTTP请求完成之后,请求模块也会发出相应类型的Action来触发Store中对于状态的变更。</p> <p>而在Flux中有个最大的陷阱就是对于数据流的破坏,我们可以在Views中访问Store中的数据,但是我们不应该在Views中修改任何Store的内部状态,所有对于状态的修改都应该通过Actions进行。作者在这里介绍了其维护的某个Flux变种的项目fluxiny。</p> <h2>Dispatcher</h2> <p><span class="img-wrap"></span></p> <p>大部分情况下我们在系统中只需要单个的Dispatcher,它是类似于粘合剂的角色将系统的其他部分有机结合在一起。Dispatcher一般而言有两个输入:Actions与Stores。其中Actions需要被直接转发给Stores,因此我们并不需要记录Actions的对象,而Stores的引用则需要保存在Dispatcher中。基于这个考虑,我们可以编写一个简单的Dispatcher:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { this._stores.push({ store: store }); }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action); }); } } } };</code></pre> <p>在上述实现中我们会发现,每个传入的<code>Store</code>对象都应该拥有一个<code>update</code>方法,因此我们在进行Store的注册时也要来检测该方法是否存在:</p> <pre><code> register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { this._stores.push({ store: store }); } }</code></pre> <p>在完成了对于Store的注册之后,下一步我们就是需要将View与Store关联起来,从而在Store发生改变的时候能够触发View的重渲染:</p> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info9/76611ea0772c4827a40ca6fb9bb61efd.jpg" target="_blank"><img alt="React设计模式:深入理解React&Redux原理套路_第1张图片" title="" src="http://img.e-com-net.com/image/info9/76611ea0772c4827a40ca6fb9bb61efd.jpg" width="620" height="245" style="border:1px solid black;"></a></span></p> <p>很多flux的实现中都会使用如下的辅助函数:</p> <pre><code> Framework.attachToStore(view, store);</code></pre> <p>不过作者并不是很喜欢这种方式,这样这样会要求View中需要调用某个具体的API,换言之,在View中就需要了解到Store的实现细节,而使得View与Store又陷入了紧耦合的境地。当开发者打算切换到其他的Flux框架时就不得不修改每个View中的相对应的API,那又会增加项目的复杂度。另一种可选的方式就是使用<code>React mixins</code>:</p> <pre><code> var View = React.createClass({ mixins: [Framework.attachToStore(store)] ... });</code></pre> <p>使用<code>mixin</code>是个不错的修改现有的React 组件而不影响其原有代码的方式,不过这种方式的缺陷在于它不能够以一种Predictable的方式去修改组件,用户的可控性较低。还有一种方式就是使用<code>React context</code>,这种方式允许我们将值跨层次地传递给React组件树中的组件而不需要了解它们处于组件树中的哪个层级。这种方式和mixins可能有相同的问题,开发者并不知道该数据从何而来。</p> <p>作者最终选用的方式即是上面提及到的Higher-Order Components模式,它建立了一个包裹函数来对现有组件进行重新打包处理:</p> <pre><code> function attachToStore(Component, store, consumer) { const Wrapper = React.createClass({ getInitialState() { return consumer(this.props, store); }, componentDidMount() { store.onChangeEvent(this._handleStoreChange); }, componentWillUnmount() { store.offChangeEvent(this._handleStoreChange); }, _handleStoreChange() { if (this.isMounted()) { this.setState(consumer(this.props, store)); } }, render() { return <Component {...this.props} {...this.state} />; } }); return Wrapper; };</code></pre> <p>其中<code>Component</code>代指我们需要附着到<code>Store</code>中的View,而<code>consumer</code>则是应该被传递给View的Store中的部分的状态,简单的用法为:</p> <pre><code> class MyView extends React.Component { ... } ProfilePage = connectToStores(MyView, store, (props, store) => ({ data: store.get('key') }));</code></pre> <p>这种模式的优势在于其有效地分割了各个模块间的职责,在该模式中Store并不需要主动地推送消息给View,而主需要简单地修改数据然后广播说我的状态已经更新了,然后由HOC去主动地抓取数据。那么在作者具体的实现中,就是选用了HOC模式:</p> <pre><code> register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer) { consumers.push(consumer); }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } }</code></pre> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info9/d72b11b8d1ea44aca4aa757739ff8362.jpg" target="_blank"><img alt="React设计模式:深入理解React&Redux原理套路_第2张图片" title="" src="http://img.e-com-net.com/image/info9/d72b11b8d1ea44aca4aa757739ff8362.jpg" width="620" height="212" style="border:1px solid black;"></a></span></p> <p>另一个常见的用户场景就是我们需要为界面提供一些默认的状态,换言之当每个<code>consumer</code>注册的时候需要提供一些初始化的默认数据:</p> <pre><code> var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; };</code></pre> <p>综上所述,最终的Dispatcher函数如下所示:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } } } };</code></pre> <h2>Actions</h2> <p>Actions就是在系统中各个模块之间传递的消息载体,作者觉得应该使用标准的Flux Action模式:</p> <pre><code> { type: 'USER_LOGIN_REQUEST', payload: { username: '...', password: '...' } }</code></pre> <p>其中的<code>type</code>属性表明该Action所代表的操作而<code>payload</code>中包含了相关的数据。另外,在某些情况下Action中没有带有Payload,因此可以使用Partial Application方式来创建标准的Action请求:</p> <pre><code> var createAction = function (type) { if (!type) { throw new Error('Please, provide action\'s type.'); } else { return function (payload) { return dispatcher.dispatch({ type: type, payload: payload }); } } }</code></pre> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info9/4f152ba972434e9fa3b2123eb353bb3c.jpg" target="_blank"><img alt="React设计模式:深入理解React&Redux原理套路_第3张图片" title="" src="http://img.e-com-net.com/image/info9/4f152ba972434e9fa3b2123eb353bb3c.jpg" width="620" height="204" style="border:1px solid black;"></a></span></p> <h2>Final Code</h2> <p>上文我们已经了解了核心的Dispatcher与Action的构造过程,那么在这里我们将这二者组合起来:</p> <pre><code> var createSubscriber = function (store) { return dispatcher.register(store); }</code></pre> <p>并且为了不直接暴露dispatcher对象,我们可以允许用户使用<code>createAction</code>与<code>createSubscriber</code>这两个函数:</p> <pre><code> var Dispatcher = function () { return { _stores: [], register: function (store) { if (!store || !store.update) { throw new Error('You should provide a store that has an `update` method.'); } else { var consumers = []; var change = function () { consumers.forEach(function (l) { l(store); }); }; var subscribe = function (consumer, noInit) { consumers.push(consumer); !noInit ? consumer(store) : null; }; this._stores.push({ store: store, change: change }); return subscribe; } return false; }, dispatch: function (action) { if (this._stores.length > 0) { this._stores.forEach(function (entry) { entry.store.update(action, entry.change); }); } } } }; module.exports = { create: function () { var dispatcher = Dispatcher(); return { createAction: function (type) { if (!type) { throw new Error('Please, provide action\'s type.'); } else { return function (payload) { return dispatcher.dispatch({ type: type, payload: payload }); } } }, createSubscriber: function (store) { return dispatcher.register(store); } } } };</code></pre> <p><span class="img-wrap"><a href="http://img.e-com-net.com/image/info9/16b4e8d44b2443b395fa828c6d7b754d.jpg" target="_blank"><img alt="React设计模式:深入理解React&Redux原理套路_第4张图片" title="" src="http://img.e-com-net.com/image/info9/16b4e8d44b2443b395fa828c6d7b754d.jpg" width="280" height="110" style="border:1px solid black;"></a></span></p> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1175676513736011776"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(redux,react.js)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1834832435699871744.htm" title="一文让你彻底弄懂Redux的基本原理以及其如何在React中使用!" target="_blank">一文让你彻底弄懂Redux的基本原理以及其如何在React中使用!</a> <span class="text-muted">tabzzz</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a> <div>文章目录什么是Redux?它有什么用Redux基本原理Redux在React中具体使用的方法ReduxToolkit(RTK)createSlice函数参数返回值示例configureStore函数参数返回值示例React-ReduxProvider组件示例React组件使用store中的数据useSelector钩子函数示例connect组件mapStateToPropsmapDispatchT</div> </li> <li><a href="/article/1834571251880914944.htm" title="redux 的 toolkit使用教程和demo" target="_blank">redux 的 toolkit使用教程和demo</a> <span class="text-muted">天下一场夢</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%A2%98/1.htm">前端面试题</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>React的redux-toolkit是一个简化Redux开发的工具包,它提供了一系列的简化方法来处理常见的Redux模式。下面我将指导你如何使用redux-toolkit创建一个简单的计数器应用。第一步:安装依赖首先你需要确保你的项目中已经安装了react,react-dom,@reduxjs/toolkit,和react-redux。你可以通过以下命令来安装它们(如果你还没有创建项目的话,可以</div> </li> <li><a href="/article/1834056834823057408.htm" title="react 全局状态管理 redux的使用" target="_blank">react 全局状态管理 redux的使用</a> <span class="text-muted">小刘的代码仓库</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>redux为全局状态管理类似vuex目录redux官网一、安装npminstallredux二、创建三、修改四、接受五、拆分、合并六、异步处理redux-thunk的使用七、redux-promise的使用八、async和await九、react-redux的使用十、修改soter的属性值十一、异步的完整代码redux官网入门Redux|Redux中文官网一、安装npminstallredux二、</div> </li> <li><a href="/article/1834036287129088000.htm" title="快速使用react 全局状态管理工具--redux" target="_blank">快速使用react 全局状态管理工具--redux</a> <span class="text-muted">蓝胖子不是胖子</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>reduxRedux是JavaScript应用中管理应用状态的工具,特别适用于复杂的、需要共享状态的中大型应用。Redux的核心思想是将应用的所有状态存储在一个单一的、不可变的状态树(statetree)中,状态只能通过触发特定的action来更新。官方文档https://cn.redux.js.org/tutorials/typescript-quick-start如果对react不了解可以看我</div> </li> <li><a href="/article/1833835531486720000.htm" title="JavaScript面试:什么是纯函数?" target="_blank">JavaScript面试:什么是纯函数?</a> <span class="text-muted">魂斗驴</span> <div>纯函数对于多种用途至关重要,包括函数式编程,可靠的并发和React+Redux应用程序。但是“纯函数”是什么意思?在我们研究纯函数是什么之前,仔细研究一下函数可能是一个好主意。观察它们的方式可能有所不同,这将使函数式编程更易于理解。什么是函数?函数是一种方法,它需要一些输入,称为自变量,并产生一些输出称为返回值。函数可以达到以下目的:映射:根据给定的输入产生一些输出。函数将输入值映射到输出值。过程</div> </li> <li><a href="/article/1831491542955683840.htm" title="react中关于token的两个场景" target="_blank">react中关于token的两个场景</a> <span class="text-muted">Now?!</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>场景一在react项目中,路由跳转前需判断是否存在token,有则正常跳转,没有则去登录页面。实现这里使用的是localstorage存储token(也可以使用redux管理token)//src\components\AuthRoute.js//封装高阶组件//有token正常跳转无token去登录页import{Navigate}from'react-router-dom'exportfunc</div> </li> <li><a href="/article/1831147307681280000.htm" title="javascript设计模式---单例模式" target="_blank">javascript设计模式---单例模式</a> <span class="text-muted">知道了啊</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a> <div>JavaScript设计模式—单例模式单例模式又称为单体模式,并提供一个访问它的全局访问点,也就是说,第二次使用同一个类创建的对象的时候,应该得到和第一次创建的对象完全相同的对象特点一个类只能生成一个实例对象提供一个全局访问点来获取这个实例案例window和documentVuex,Redux和Router全局loading缺点确保在整个应用中,只有一个实例存在,而且该实例需要被全局访问时。但是使</div> </li> <li><a href="/article/1831030072568541184.htm" title="微信小程序 全局共享数据 Mobx 在页面及组件上使用" target="_blank">微信小程序 全局共享数据 Mobx 在页面及组件上使用</a> <span class="text-muted">尚梦</span> <a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a> <div>一前言在小程序中,常常有些数据需要在几个页面或组件中共享,对于这样的数据,在web开发中,有些朋友使用过redux、vuex之类的状态管理框架。在小程序开发中,也有不少朋友喜欢用MobX。二mobx引入npminstall--savemobx-miniprogrammobx-miniprogram-bindingsnpm命令执行完后,记得在开发者工具的项目中点一下菜单栏中的工具-构建npm。三创建</div> </li> <li><a href="/article/1830678335999537152.htm" title="redux基础" target="_blank">redux基础</a> <span class="text-muted">小宇cool</span> <div>1.什么是Redux?Redux是JavaScript状态容器,提供了预测的状态管理,.可以让你构建一致化的应用,应用于不同的环境(客户端,服务器,元素应用)2.ActionAction是把数据从应用,传到Stroe的有效载荷.他是Stroe的唯一来源,一般来是你会通过troe.dispath将action传到stroe中action相当于一个触发器,只有当我们触发了action,我们才能对sta</div> </li> <li><a href="/article/1830646621059248128.htm" title="react.js" target="_blank">react.js</a> <span class="text-muted">涔溪</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>一、create-react-app全局安装create-react-app$npminstall-gcreate-react-app创建一个项目$create-react-appyour-app注意命名方式CreatinganewReactappin/dir/your-app.Installingpackages.Thismighttakeacoupleofminutes.安装过程较慢,Inst</div> </li> <li><a href="/article/1830045890577002496.htm" title="React Native优质开源项目推荐与解析" target="_blank">React Native优质开源项目推荐与解析</a> <span class="text-muted">concisedistinct</span> <a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/reactnative/1.htm">reactnative</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a> <div>目录2.ReactNative的优势2.1.跨平台开发2.2.热更新2.3.丰富的社区资源2.4.优秀的性能3.优质开源项目推荐3.1.ReactNavigation3.1.1项目简介3.1.2特点和优势3.1.3应用场景3.2.Redux3.2.1项目简介3.2.2特点和优势3.2.3应用场景3.3.ReactNativeElements3.3.1项目简介3.3.2特点和优势3.3.3应用场景3</div> </li> <li><a href="/article/1829977213940887552.htm" title="React+Redux+Ant Design+TypeScript 电子商务实战-客户端应用 04 首页产品展示、搜索、筛选和产品详情" target="_blank">React+Redux+Ant Design+TypeScript 电子商务实战-客户端应用 04 首页产品展示、搜索、筛选和产品详情</a> <span class="text-muted">皮蛋很白</span> <a class="tag" taget="_blank" href="/search/%E5%AE%9E%E6%88%98/1.htm">实战</a><a class="tag" taget="_blank" href="/search/typescript/1.htm">typescript</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a> <div>构建首页布局搜索布局//src\components\core\Search.tsximport{Button,Col,Divider,Form,Input,Row,Select}from'antd'importProductItemfrom'./ProductItem'constSearch=()=>{return(所有分类搜索)}exportdefaultSearch搜索结果展示的产品组件//</div> </li> <li><a href="/article/1829958807317475328.htm" title="React学习day18" target="_blank">React学习day18</a> <span class="text-muted">我在东软打代码</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a> <div>Provider批量传递store对象,求和案例react-redux优化容器组件和UI组件整合一个文件。无需自己给容器组件传递store,给包裹一个即可。使用react-redux后也不用自己再检测redux中状态的改变,容器组件可以自动完成这个工作。.mapDispatchToProps也可以简单的写一个对象一个组件要和redux“打交道”要经过几步(1)定义好UI组件—不暴露(2)引入con</div> </li> <li><a href="/article/1829677818624176128.htm" title="React基础面试题" target="_blank">React基础面试题</a> <span class="text-muted">涔溪</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>React面试题以下是面试官最有可能问到的50个React面试题和答案。为方便你学习,我对它们进行了分类:基本知识React组件ReactReduxReact路由基本知识1.区分RealDOM和VirtualDOMRealDOMVirtualDOM1.更新缓慢。1.更新更快。2.可以直接更新HTML。2.无法直接更新HTML。3.如果元素更新,则创建新DOM。3.如果元素更新,则更新JSX。4.D</div> </li> <li><a href="/article/1829606080011923456.htm" title="2024最新最全的React面试题" target="_blank">2024最新最全的React面试题</a> <span class="text-muted">二丫骑士qq</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>1.react和vue的区别?(1)设计理念:React:更倾向于函数式编程思想,推崇组件的不可变性和单向数据流。Vue:结合了响应式编程和模板系统,致力于简化开发过程。(2)核心库与生态系统:React:React本身只关注UI层,但它有一个庞大的生态系统,例如Redux、MobX等用于状态管理,以及ReactRouter用于路由处理。Vue:Vue是一个更完整的解决方案,它的核心库除了视图层,</div> </li> <li><a href="/article/1828446950924578816.htm" title="vue设置全局背景图_vue开发使用笔记" target="_blank">vue设置全局背景图_vue开发使用笔记</a> <span class="text-muted">weixin_39629780</span> <a class="tag" taget="_blank" href="/search/vue%E8%AE%BE%E7%BD%AE%E5%85%A8%E5%B1%80%E8%83%8C%E6%99%AF%E5%9B%BE/1.htm">vue设置全局背景图</a> <div>在SPA单页面组件的开发中Vue的vuex和React的Redux都统称为同一状态管理,个人的理解是全局状态管理更合适;简单的理解就是你在state中定义了一个数据之后,你可以在所在项目中的任何一个组件里进行获取、进行修改,并且你的修改可以得到全局的响应变更。下面咱们一步一步地剖析下vuex的使用:首先要安装、使用vuex首先在vue2.0+你的vue-cli项目中安装vuex:npminstal</div> </li> <li><a href="/article/1828080032459878400.htm" title="React.js如何使用Bootstrap" target="_blank">React.js如何使用Bootstrap</a> <span class="text-muted">Vesper63</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/bootstrap/1.htm">bootstrap</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>在React.js项目中使用Bootstrap有多种方法,主要包括直接引入BootstrapCSS文件和使用ReactBootstrap库。下面将详细介绍这两种方法。方法一:直接引入BootstrapCSS文件这是最简单的方式,只需在项目中引入Bootstrap的CSS文件即可。安装Bootstrap:你可以通过npm或yarn安装Bootstrap:npminstallbootstrap或者:y</div> </li> <li><a href="/article/1827945096381820928.htm" title="外卖系统定制开发:技术选型与架构设计要点" target="_blank">外卖系统定制开发:技术选型与架构设计要点</a> <span class="text-muted">万岳科技系统开发</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>随着外卖行业的迅速发展,餐饮企业需要一个高效、稳定、可扩展的外卖系统来满足日益增长的用户需求。本文将探讨外卖系统定制开发的技术选型与架构设计要点,并提供一些示例代码来说明关键技术的实现。一、技术选型1.前端技术选型外卖系统的前端需要具备良好的用户体验和快速响应能力。常用的前端技术包括:框架:React、Vue.js或Angular状态管理:Redux、VuexCSS预处理器:Sass、Less打包</div> </li> <li><a href="/article/1827748985683668992.htm" title="Flutter 第三方库" target="_blank">Flutter 第三方库</a> <span class="text-muted">creazylee</span> <div>flutter_redux:在Flutter上使用Redux。flutter_webview_plugin:WebView插件。flutter_amap:高德地图Flutter插件。flutter_alipay:支付宝支付Flutter插件。amap_location:高德地图定位插件。flutter_mobile_vision:二维码识别神库,支持人面识别。barcode_scan:二维码识别库</div> </li> <li><a href="/article/1827431712859189248.htm" title="前端精髓-React" target="_blank">前端精髓-React</a> <span class="text-muted">hulovelove</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a> <div>目录React的几大原理:diff原理React的工作流程大致如下:React为什么要使用reduxRedux基本原理:Redux的核心概念包括:Redux的工作流程大致如下:整个redux工作流程:Reducer为什么要返回一个新的state为什么要用State?reducer如何管理数据?React异常获取-错误边界(ErrorBoundary):React严格模式开启与关闭?严格模式有什么好</div> </li> <li><a href="/article/1826725222166917120.htm" title="从零开始开发跑腿配送系统:技术选型与架构设计" target="_blank">从零开始开发跑腿配送系统:技术选型与架构设计</a> <span class="text-muted">万岳科技系统开发</span> <a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>开发一个跑腿配送系统涉及多个技术栈和模块,从前端到后端,再到数据库和实时通信,每一个环节都至关重要。本文将详细介绍从零开始开发跑腿配送系统的技术选型与架构设计,并提供部分代码示例以帮助理解。一、技术选型前端技术:React:用于构建用户界面,具有组件化和高效的特点。Redux:用于状态管理,便于管理复杂的应用状态。AntDesign:提供一套美观的UI组件,提升开发效率和用户体验。后端技术:Nod</div> </li> <li><a href="/article/1771872627095306240.htm" title="使用 Redux 管理 React 应用状态" target="_blank">使用 Redux 管理 React 应用状态</a> <span class="text-muted">JudithHuang</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83/1.htm">从入门到放弃</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>使用Redux管理React应用状态在复杂的React应用中,管理组件状态变得越来越复杂,这时候引入Redux可以帮助我们更好地管理状态。Redux是一个可预测状态容器,它可以帮助我们统一管理应用的状态,使得状态变化更加可控。本文将介绍如何在React应用中使用Redux。Redux简介Redux是一个状态管理库,它提供了一种可预测的状态管理方案。Redux的核心思想是将应用的状态存储在一个单一的</div> </li> <li><a href="/article/1769703173628428288.htm" title="React核心⼊⻔-lesson1" target="_blank">React核心⼊⻔-lesson1</a> <span class="text-muted">IT帮</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>自学React从入门到精通,从使用到写源码React⼊⻔课堂⽬标资源起步⽂件结构⽂件结构⼀览React和ReactDomJSX使⽤JSX组件组件的两种形式class组件function组件组件状态管理类组件中的状态管理函数组件中的状态管理事件处理组件通信Props属性传递contextredux⽣命周期变更缘由新引⼊了两个新的⽣命周期函数:getDerivedStateFromProps,getS</div> </li> <li><a href="/article/1765946688872210432.htm" title="Superset二次开发之Superset架构理解" target="_blank">Superset二次开发之Superset架构理解</a> <span class="text-muted">aimmon</span> <a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/superset/1.htm">superset</a><a class="tag" taget="_blank" href="/search/BI/1.htm">BI</a> <div>技术框架框架作用前端React构建用户界面的JavaScript库ReduxJavaScript应用的状态管理库,管理组件间的状态共享Webpack前端资源打包工具BabelJavaScript编译器D3.js数据可视化的JavaScript库后端Flask轻量级的Pythonweb框架,处理HTTP请求、路由以及其他Web服务功能SQLAlchemySQL工具包和对象关系映射(ORM)工具,处理</div> </li> <li><a href="/article/1759955709916704768.htm" title="React Hook “useSelector“ cannot be called at the top level. React Hooks must" target="_blank">React Hook “useSelector“ cannot be called at the top level. React Hooks must</a> <span class="text-muted">poguanba</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>一般报这个错的话,就是useSelector写在了函数组件外边解决办法就是//项目的根组件import{useSelector}from"react-redux";functionApp(){constcount=useSelector(state=>state.counter)returnthisistitle{count};}exportdefaultApp;</div> </li> <li><a href="/article/1759950762793857024.htm" title="react起源" target="_blank">react起源</a> <span class="text-muted">lemmo</span> <div>简介React(有时叫React.js或ReactJS),是一个为数据提供渲染为HTML视图的开源JavaScript库。React视图通常采用包含以自定义HTML标记规定的其他组件的组件渲染。React为程序员提供了一种子组件不能直接影响外层组件("dataflowsdown")的模型,数据改变时对HTML文档的有效更新,和现代单页应用中组件之间干净的分离。它由Facebook、Instagra</div> </li> <li><a href="/article/1759892840671965184.htm" title="2024前端面试准备之uniapp篇" target="_blank">2024前端面试准备之uniapp篇</a> <span class="text-muted">前端fighter</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a> <div>全文链接!!!!!!!1.UniApp和其他跨平台框架(如ReactNative、Flutter)有什么区别?语言和技术栈:UniApp使用Vue.js作为开发语言和技术栈,而ReactNative使用React.js,Flutter使用Dart语言。开发者可以根据自己的技术背景和偏好选择合适的框架。性能和体验:UniApp的性能和用户体验相对较好,因为它使用原生渲染技术,可以实现更接近原生应用的</div> </li> <li><a href="/article/1759641667763269632.htm" title="Ant Design 组件学习经验" target="_blank">Ant Design 组件学习经验</a> <span class="text-muted">zhulichao</span> <div>Tree组件参考TreeSelect异步加载数据使用redux时,TreeSelect异步加载数据需要通过触发action调用后台获取数据,根据reducer更新的state显示出加载的数据。需添加loadData属性,值为一个方法,如onLoadData,内容如下。这个函数的返回值好像必须是一个Promise对象,如果不这么写,会报UncaughtTypeError:Cannotreadprop</div> </li> <li><a href="/article/1759629324341833728.htm" title="快速创建react项目." target="_blank">快速创建react项目.</a> <span class="text-muted">River_tong</span> <div>react简介说起react,我相信大家都对它有一定的了解,react目前是前端界非常流行的一个框架了,react它产生了很多相关的技术,比如:我们常说的react.js,我们可以用react语法来编写一些网页版应用,reactnative这门技术使得我们可以用react语法来编写原生应用,reactVR可以借助react的语法来编写一些VR相关的应用或者说全景视图这样的应用。react开发环境搭</div> </li> <li><a href="/article/1759524950244421632.htm" title="react-redux 基本原理 & 使用redux 处理异步逻辑" target="_blank">react-redux 基本原理 & 使用redux 处理异步逻辑</a> <span class="text-muted">廖雪青</span> <div>Redux出现的背景随着对React使用的深入,你会发现组件级别的state,和从上而下传递的props这两个状态机制,无法满足复杂功能的需要,例如跨层级之间的组件的数据共享和传递,Redux应运而生。state应用&redux应用对比左图是单个React组件,它的状态可以用内部的state来维护,而且这个state在组件外部是无法访问的。右图则是使用Redux的场景,用全局唯一的Store维护了</div> </li> <li><a href="/article/28.htm" title="如何用ruby来写hadoop的mapreduce并生成jar包" target="_blank">如何用ruby来写hadoop的mapreduce并生成jar包</a> <span class="text-muted">wudixiaotie</span> <a class="tag" taget="_blank" href="/search/mapreduce/1.htm">mapreduce</a> <div>ruby来写hadoop的mapreduce,我用的方法是rubydoop。怎么配置环境呢: 1.安装rvm:     不说了 网上有 2.安装ruby:     由于我以前是做ruby的,所以习惯性的先安装了ruby,起码调试起来比jruby快多了。 3.安装jruby:     rvm install jruby然后等待安</div> </li> <li><a href="/article/155.htm" title="java编程思想 -- 访问控制权限" target="_blank">java编程思想 -- 访问控制权限</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6%E6%9D%83%E9%99%90/1.htm">访问控制权限</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a> <div>访问权限是java中一个比较中要的知识点,它规定者什么方法可以访问,什么不可以访问   一:包访问权限;   自定义包: package com.wj.control; //包 public class Demo { //定义一个无参的方法 public void DemoPackage(){ System.out.println("调用</div> </li> <li><a href="/article/282.htm" title="[生物与医学]请审慎食用小龙虾" target="_blank">[生物与医学]请审慎食用小龙虾</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E7%94%9F%E7%89%A9/1.htm">生物</a> <div>      现在的餐馆里面出售的小龙虾,有一些是在野外捕捉的,这些小龙虾身体里面可能带有某些病毒和细菌,人食用以后可能会导致一些疾病,严重的甚至会死亡.....      所以,参加聚餐的时候,最好不要点小龙虾...就吃养殖的猪肉,牛肉,羊肉和鱼,等动物蛋白质     </div> </li> <li><a href="/article/409.htm" title="org.apache.jasper.JasperException: Unable to compile class for JSP:" target="_blank">org.apache.jasper.JasperException: Unable to compile class for JSP:</a> <span class="text-muted">商人shang</span> <a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a><a class="tag" taget="_blank" href="/search/2.2/1.htm">2.2</a><a class="tag" taget="_blank" href="/search/jdk1.8/1.htm">jdk1.8</a> <div>环境: jdk1.8    maven  tomcat7-maven-plugin  2.0 原因: tomcat7-maven-plugin  2.0 不知吃 jdk 1.8,换成 tomcat7-maven-plugin  2.2就行,即     <plugin> </div> </li> <li><a href="/article/536.htm" title="你的垃圾你处理掉了吗?GC" target="_blank">你的垃圾你处理掉了吗?GC</a> <span class="text-muted">oloz</span> <a class="tag" taget="_blank" href="/search/GC/1.htm">GC</a> <div>前序:本人菜鸟,此文研究学习来自网络,各位牛牛多指教  1.垃圾收集算法的核心思想   Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用。   垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别</div> </li> <li><a href="/article/663.htm" title="shiro 和 SESSSION" target="_blank">shiro 和 SESSSION</a> <span class="text-muted">杨白白</span> <a class="tag" taget="_blank" href="/search/shiro/1.htm">shiro</a> <div>shiro 在web项目里默认使用的是web容器提供的session,也就是说shiro使用的session是web容器产生的,并不是自己产生的,在用于非web环境时可用其他来源代替。在web工程启动的时候它就和容器绑定在了一起,这是通过web.xml里面的shiroFilter实现的。通过session.getSession()方法会在浏览器cokkice产生JESSIONID,当关闭浏览器,此</div> </li> <li><a href="/article/790.htm" title="移动互联网终端 淘宝客如何实现盈利" target="_blank">移动互联网终端 淘宝客如何实现盈利</a> <span class="text-muted">小桔子</span> <a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8B%95%E5%AE%A2%E6%88%B6%E7%AB%AF/1.htm">移動客戶端</a><a class="tag" taget="_blank" href="/search/%E6%B7%98%E5%AE%A2/1.htm">淘客</a><a class="tag" taget="_blank" href="/search/%E6%B7%98%E5%AF%B6App/1.htm">淘寶App</a> <div>       2012年淘宝联盟平台为站长和淘宝客带来的分成收入突破30亿元,同比增长100%。而来自移动端的分成达1亿元,其中美丽说、蘑菇街、果库、口袋购物等App运营商分成近5000万元。 可以看出,虽然目前阶段PC端对于淘客而言仍旧是盈利的大头,但移动端已经呈现出爆发之势。而且这个势头将随着智能终端(手机,平板)的加速普及而更加迅猛</div> </li> <li><a href="/article/917.htm" title="wordpress小工具制作" target="_blank">wordpress小工具制作</a> <span class="text-muted">aichenglong</span> <a class="tag" taget="_blank" href="/search/wordpress/1.htm">wordpress</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E5%B7%A5%E5%85%B7/1.htm">小工具</a> <div>wordpress 使用侧边栏的小工具,很方便调整页面结构 小工具的制作过程 1 在自己的主题文件中新建一个文件夹(如widget),在文件夹中创建一个php(AWP_posts-category.php) 小工具是一个类,想侧边栏一样,还得使用代码注册,他才可以再后台使用,基本的代码一层不变 <?php class AWP_Post_Category extends WP_Wi</div> </li> <li><a href="/article/1044.htm" title="JS微信分享" target="_blank">JS微信分享</a> <span class="text-muted">AILIKES</span> <a class="tag" taget="_blank" href="/search/js/1.htm">js</a> <div>// 所有功能必须包含在 WeixinApi.ready 中进行    WeixinApi.ready(function(Api) {        // 微信分享的数据            var wxData = {       &nb</div> </li> <li><a href="/article/1171.htm" title="封装探讨" target="_blank">封装探讨</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/JAVA%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1+%E5%B0%81%E8%A3%85/1.htm">JAVA面向对象 封装</a> <div>//封装   属性 方法 将某些东西包装在一起,通过创建对象或使用静态的方法来调用,称为封装;封装其实就是有选择性地公开或隐藏某些信息,它解决了数据的安全性问题,增加代码的可读性和可维护性   在 Aname类中申明三个属性,将其封装在一个类中:通过对象来调用   例如   1: //属性 将其设为私有 姓名 name 可以公开 </div> </li> <li><a href="/article/1298.htm" title="jquery radio/checkbox change事件不能触发的问题" target="_blank">jquery radio/checkbox change事件不能触发的问题</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a> <div>我想让radio来控制当前我选择的是机动车还是特种车,如下所示:  <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"><</div> </li> <li><a href="/article/1425.htm" title="AngularJS中安全性措施" target="_blank">AngularJS中安全性措施</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8%E6%80%A7/1.htm">安全性</a><a class="tag" taget="_blank" href="/search/XSRF/1.htm">XSRF</a><a class="tag" taget="_blank" href="/search/JSON%E6%BC%8F%E6%B4%9E/1.htm">JSON漏洞</a> <div>        在使用web应用中,安全性是应该首要考虑的一个问题。AngularJS提供了一些辅助机制,用来防护来自两个常见攻击方向的网络攻击。 一.JSON漏洞         当使用一个GET请求获取JSON数组信息的时候(尤其是当这一信息非常敏感,</div> </li> <li><a href="/article/1552.htm" title="[Maven学习笔记九]Maven发布web项目" target="_blank">[Maven学习笔记九]Maven发布web项目</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a> <div>基于Maven的web项目的标准项目结构 user-project     user-core     user-service     user-web        src      </div> </li> <li><a href="/article/1679.htm" title="【Hive七】Hive用户自定义聚合函数(UDAF)" target="_blank">【Hive七】Hive用户自定义聚合函数(UDAF)</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/hive/1.htm">hive</a> <div>用户自定义聚合函数,用户提供的多个入参通过聚合计算(求和、求最大值、求最小值)得到一个聚合计算结果的函数。 问题:UDF也可以提供输入多个参数然后输出一个结果的运算,比如加法运算add(3,5),add这个UDF需要实现UDF的evaluate方法,那么UDF和UDAF的实质分别究竟是什么?   Double evaluate(Double a, Double b)  </div> </li> <li><a href="/article/1806.htm" title="通过 nginx-lua 给 Nginx 增加 OAuth 支持" target="_blank">通过 nginx-lua 给 Nginx 增加 OAuth 支持</a> <span class="text-muted">ronin47</span> <div>前言:我们使用Nginx的Lua中间件建立了OAuth2认证和授权层。如果你也有此打算,阅读下面的文档,实现自动化并获得收益。SeatGeek 在过去几年中取得了发展,我们已经积累了不少针对各种任务的不同管理接口。我们通常为新的展示需求创建新模块,比如我们自己的博客、图表等。我们还定期开发内部工具来处理诸如部署、可视化操作及事件处理等事务。在处理这些事务中,我们使用了几个不同的接口来认证: &n</div> </li> <li><a href="/article/1933.htm" title="利用tomcat-redis-session-manager做session同步时自定义类对象属性保存不上的解决方法" target="_blank">利用tomcat-redis-session-manager做session同步时自定义类对象属性保存不上的解决方法</a> <span class="text-muted">bsr1983</span> <a class="tag" taget="_blank" href="/search/session/1.htm">session</a> <div>在利用tomcat-redis-session-manager做session同步时,遇到了在session保存一个自定义对象时,修改该对象中的某个属性,session未进行序列化,属性没有被存储到redis中。 在 tomcat-redis-session-manager的github上有如下说明: Session Change Tracking As noted in the &qu</div> </li> <li><a href="/article/2060.htm" title="《代码大全》表驱动法-Table Driven Approach-1" target="_blank">《代码大全》表驱动法-Table Driven Approach-1</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>关于Table Driven Approach的一篇非常好的文章: http://www.codeproject.com/Articles/42732/Table-driven-Approach package com.ljn.base; import java.util.Random; public class TableDriven { public </div> </li> <li><a href="/article/2187.htm" title="Sybase封锁原理" target="_blank">Sybase封锁原理</a> <span class="text-muted">chicony</span> <a class="tag" taget="_blank" href="/search/Sybase/1.htm">Sybase</a> <div>       昨天在操作Sybase IQ12.7时意外操作造成了数据库表锁定,不能删除被锁定表数据也不能往其中写入数据。由于着急往该表抽入数据,因此立马着手解决该表的解锁问题。     无奈此前没有接触过Sybase IQ12.7这套数据库产品,加之当时已属于下班时间无法求助于支持人员支持,因此只有借助搜索引擎强大的</div> </li> <li><a href="/article/2314.htm" title="java异常处理机制" target="_blank">java异常处理机制</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>java异常关键字有以下几个,分别为 try catch final throw throws 他们的定义分别为 try:    Opening exception-handling statement. catch:  Captures the exception. finally: Runs its code before terminating</div> </li> <li><a href="/article/2441.htm" title="hive 数据插入DML语法汇总" target="_blank">hive 数据插入DML语法汇总</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/hive/1.htm">hive</a><a class="tag" taget="_blank" href="/search/DML/1.htm">DML</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8F%92%E5%85%A5/1.htm">数据插入</a> <div>Hive的数据插入DML语法汇总1、Loading files into tables语法:1) LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]解释:1)、上面命令执行环境为hive客户端环境下: hive>l</div> </li> <li><a href="/article/2568.htm" title="工厂设计模式" target="_blank">工厂设计模式</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a> <div>  使用设计模式是促进最佳实践和良好设计的好办法。设计模式可以提供针对常见的编程问题的灵活的解决方案。 工厂模式 工厂模式(Factory)允许你在代码执行时实例化对象。它之所以被称为工厂模式是因为它负责“生产”对象。工厂方法的参数是你要生成的对象对应的类名称。 Example #1 调用工厂方法(带参数) <?phpclass Example{ </div> </li> <li><a href="/article/2695.htm" title="mysql字符串查找函数" target="_blank">mysql字符串查找函数</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>  FIND_IN_SET(str,strlist) 假如字符串str 在由N 子链组成的字符串列表strlist 中,则返回值的范围在1到 N 之间。一个字符串列表就是一个由一些被‘,’符号分开的自链组成的字符串。如果第一个参数是一个常数字符串,而第二个是type SET列,则   FIND_IN_SET() 函数被优化,使用比特计算。如果str不在strlist 或st</div> </li> <li><a href="/article/2822.htm" title="jvm内存管理" target="_blank">jvm内存管理</a> <span class="text-muted">easterfly</span> <a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a> <div>一、JVM堆内存的划分 分为年轻代和年老代。年轻代又分为三部分:一个eden,两个survivor。 工作过程是这样的:e区空间满了后,执行minor gc,存活下来的对象放入s0, 对s0仍会进行minor gc,存活下来的的对象放入s1中,对s1同样执行minor gc,依旧存活的对象就放入年老代中; 年老代满了之后会执行major gc,这个是stop the word模式,执行</div> </li> <li><a href="/article/2949.htm" title="CentOS-6.3安装配置JDK-8" target="_blank">CentOS-6.3安装配置JDK-8</a> <span class="text-muted">gengzg</span> <a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a> <div>JAVA_HOME=/usr/java/jdk1.8.0_45 JRE_HOME=/usr/java/jdk1.8.0_45/jre PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib export JAVA_HOME</div> </li> <li><a href="/article/3076.htm" title="【转】关于web路径的获取方法" target="_blank">【转】关于web路径的获取方法</a> <span class="text-muted">huangyc1210</span> <a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E8%B7%AF%E5%BE%84/1.htm">路径</a> <div>假定你的web application 名称为news,你在浏览器中输入请求路径:  http://localhost:8080/news/main/list.jsp  则执行下面向行代码后打印出如下结果:  1、 System.out.println(request.getContextPath()); //可返回站点的根路径。也就是项</div> </li> <li><a href="/article/3203.htm" title="php里获取第一个中文首字母并排序" target="_blank">php里获取第一个中文首字母并排序</a> <span class="text-muted">远去的渡口</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a> <div>很久没来更新博客了,还是觉得工作需要多总结的好。今天来更新一个自己认为比较有成就的问题吧。 最近在做储值结算,需求里结算首页需要按门店的首字母A-Z排序。我的数据结构原本是这样的: Array ( [0] => Array ( [sid] => 2885842 [recetcstoredpay] =&g</div> </li> <li><a href="/article/3330.htm" title="java内部类" target="_blank">java内部类</a> <span class="text-muted">hm4123660</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%86%85%E9%83%A8%E7%B1%BB/1.htm">内部类</a><a class="tag" taget="_blank" href="/search/%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB/1.htm">匿名内部类</a><a class="tag" taget="_blank" href="/search/%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB/1.htm">成员内部类</a><a class="tag" taget="_blank" href="/search/%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB/1.htm">方法内部类</a> <div>      在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。内部类可以间接解决多继承问题,可以使用内部类继承一个类,外部类继承一个类,实现多继承。      &nb</div> </li> <li><a href="/article/3457.htm" title="Caused by: java.lang.IncompatibleClassChangeError: class org.hibernate.cfg.Exten" target="_blank">Caused by: java.lang.IncompatibleClassChangeError: class org.hibernate.cfg.Exten</a> <span class="text-muted">zhb8015</span> <div>maven pom.xml关于hibernate的配置和异常信息如下,查了好多资料,问题还是没有解决。只知道是包冲突,就是不知道是哪个包....遇到这个问题的分享下是怎么解决的。。   maven pom:   <dependency> <groupId>org.hibernate</groupId> <ar</div> </li> <li><a href="/article/3584.htm" title="Spark 性能相关参数配置详解-任务调度篇" target="_blank">Spark 性能相关参数配置详解-任务调度篇</a> <span class="text-muted">Stark_Summer</span> <a class="tag" taget="_blank" href="/search/spark/1.htm">spark</a><a class="tag" taget="_blank" href="/search/cache/1.htm">cache</a><a class="tag" taget="_blank" href="/search/cpu/1.htm">cpu</a><a class="tag" taget="_blank" href="/search/%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6/1.htm">任务调度</a><a class="tag" taget="_blank" href="/search/yarn/1.htm">yarn</a> <div>随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化。   由于篇幅较长,所以在这里分篇组织,如果要看最新完整的网页版内容,可以戳这里:http://spark-config.readthedocs.org/,主要是便</div> </li> <li><a href="/article/3711.htm" title="css3滤镜" target="_blank">css3滤镜</a> <span class="text-muted">wangkeheng</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>经常看到一些网站的底部有一些灰色的图标,鼠标移入的时候会变亮,开始以为是js操作src或者bg呢,搜索了一下,发现了一个更好的方法:通过css3的滤镜方法。 html代码: <a href='' class='icon'><img src='utv.jpg' /></a> css代码: .icon{-webkit-filter: graysc</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>