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/1892183773232033792.htm" title="redux、react-redux、redux-thunk、redux-saga对比" target="_blank">redux、react-redux、redux-thunk、redux-saga对比</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/redux/1.htm">redux</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>reduxredux工作流程示意图actions函数形式,返回action对象,通常具有type属性。负责指令的生成,页面通过store.dispatch(action)向store发送数据修改的请求。reducers一个纯函数,接收两个参数(previousState,action)第一个表示修改之前的state的值,action是上一步页面通过store.dispatch(action)向st</div> </li> <li><a href="/article/1892177468253597696.htm" title="redux中间件-redux-thunk" target="_blank">redux中间件-redux-thunk</a> <span class="text-muted">#清词#</span> <a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/1.htm">中间件</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>今天,让我们一起揭开redux中间件-redux-thunk的神秘面纱。本次小文章将会以任务驱动的形式去逐步讲解thunk及其在redux中的使用,这样易于理解,有理有据能够化抽象为具体。首先,为什么要使用redux中间件?什么是中间件?中间件有什么作用呢?redux是一个通用的JavaScript状态管理容器。对于state的变化是通过触发dispatch一个action,然后最交给reduce</div> </li> <li><a href="/article/1892174694283538432.htm" title="redux中间件saga和thunk的区别" target="_blank">redux中间件saga和thunk的区别</a> <span class="text-muted">江醉鱼</span> <a class="tag" taget="_blank" href="/search/react/1.htm">react</a> <div>redux中的action仅支持原始对象(plainobject),处理有副作用的action,需要使用中间件。中间件可以在发出action,到reducer函数接受action之间,执行具有副作用的操作。之前一直使用redux-thunk处理异步等副作用操作,在action中处理异步等副作用操作,此时的action是一个函数,以dispatch,getState作为形参,函数体内的部分可以执行异</div> </li> <li><a href="/article/1892169397628366848.htm" title="redux-saga和redux-thunk的区别与使用场景?" target="_blank">redux-saga和redux-thunk的区别与使用场景?</a> <span class="text-muted">小安吖~</span> <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><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</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%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>Redux-Saga和Redux-Thunk是两个常用的Redux中间件,用于处理异步操作。它们具有一些区别和适用场景。区别:编码风格:Redux-Saga使用Generator函数来处理异步操作,而Redux-Thunk使用函数来处理异步操作。控制流程:Redux-Saga提供了强大的控制流程能力,可以以同步的方式表达复杂的异步逻辑。它使用监听器和yield语句来控制和组织异步操作的流程。而Re</div> </li> <li><a href="/article/1892005951054082048.htm" title="Redux-Loop 教程:将Elm架构的力量带入Redux" target="_blank">Redux-Loop 教程:将Elm架构的力量带入Redux</a> <span class="text-muted">柯兰妃Jimmy</span> <div>Redux-Loop教程:将Elm架构的力量带入Reduxredux-loopAlibrarythatportsElm'seffectsystemtoRedux项目地址:https://gitcode.com/gh_mirrors/re/redux-loop项目介绍Redux-Loop是一个将Elm架构中效应系统移植到Redux的库。它革新了处理副作用的方式,允许你在Reducers中通过返回的方</div> </li> <li><a href="/article/1891604280536788992.htm" title="初识redux" target="_blank">初识redux</a> <span class="text-muted">未命名小孩</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%9F%A5%E8%AF%86/1.htm">前端知识</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/js/1.htm">js</a><a class="tag" taget="_blank" href="/search/typescript/1.htm">typescript</a> <div>Redux是一个用于管理JavaScript应用程序状态的可预测状态容器核心概念1.单一数据源整个应用的状态被存储在一个单一的对象树(store)中,这个对象树位于唯一的store里。创建store:conststore=createStore(reducer)2.状态是只读的唯一改变状态的方法是触发一个action,action是一个描述状态变化的纯对象。这保证了所有的状态变化都是可追踪的。一个</div> </li> <li><a href="/article/1891083574577262592.htm" title="Flux架构及Redux实践" target="_blank">Flux架构及Redux实践</a> <span class="text-muted">GbkMobile</span> <a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>随着前端应用的复杂性不断增加,有效管理应用状态和数据流变得至关重要。Flux架构及其最流行的实现之一Redux,为前端开发人员提供了一种可靠且可扩展的解决方案。本文将深入浅出地介绍Flux架构的核心概念,并通过实际的Redux实践示例来帮助读者更好地理解和应用这些概念。什么是Flux架构?Flux是一种前端应用架构模式,旨在解决传统MVC(Model-View-Controller)模式在大型应用</div> </li> <li><a href="/article/1891065672667033600.htm" title="探索Redux:构建可预测、可测试的JavaScript应用" target="_blank">探索Redux:构建可预测、可测试的JavaScript应用</a> <span class="text-muted">黎杉娜Torrent</span> <div>探索Redux:构建可预测、可测试的JavaScript应用learn-redux:boom:ComprehensiveNotesforLearning(howtouse)ReduxtomanagestateinyourWeb/Mobile(React.js)Apps.项目地址:https://gitcode.com/gh_mirrors/le/learn-redux项目介绍在现代Web开发中,J</div> </li> <li><a href="/article/1890297731084251136.htm" title="react和react-native中redux @reduxjs/toolkit的使用" target="_blank">react和react-native中redux @reduxjs/toolkit的使用</a> <span class="text-muted">九段刀客</span> <a class="tag" taget="_blank" href="/search/ReactNative/1.htm">ReactNative</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/native/1.htm">native</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>下面的示例是在react-native中使用yarnaddreact-redux@reduxjs/toolkit一、store中store/module/dict.jsimport{createSlice}from'@reduxjs/toolkit';import{api_dict_biz}from'~/api/dict'</div> </li> <li><a href="/article/1890289781762486272.htm" title="react-redux和@reduxjs/toolkit应用案例" target="_blank">react-redux和@reduxjs/toolkit应用案例</a> <span class="text-muted">前端小云儿</span> <a class="tag" taget="_blank" href="/search/React%E6%8A%80%E8%83%BD%E5%A4%A7%E5%85%A8/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/javascript/1.htm">javascript</a> <div>1首先安装npminstall@reduxjs/toolkitreact-dedux或者pnpminstall@reduxjs/toolkitreact-dedux2新建文件夹,写模块内容3tab.jsimport{createSlice}from"@reduxjs/toolkit";consttabSlice=createSlice({name:"tab",initialState:{isCol</div> </li> <li><a href="/article/1889687573337534464.htm" title="告别前端状态管理噩梦:AI代码生成器如何简化你的工作" target="_blank">告别前端状态管理噩梦:AI代码生成器如何简化你的工作</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>前端开发,尤其是大型项目的开发,常常被复杂的AI写代码工具所困扰。状态管理,作为前端开发的核心难题之一,更是让无数开发者头疼不已。代码维护困难、数据流追踪不易、逻辑混乱等问题层出不穷,严重影响开发效率和项目质量。高效的前端状态管理至关重要,而智能化解决方案的出现,正为我们提供了一条新的出路。前端状态管理的智能模式识别:突破传统方案的局限传统的方案,例如Redux、Vuex等,虽然在一定程度上解决了</div> </li> <li><a href="/article/1889679745512173568.htm" title="告别前端状态管理噩梦:AI代码生成器如何简化你的工作" target="_blank">告别前端状态管理噩梦:AI代码生成器如何简化你的工作</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>前端开发,尤其是大型项目的开发,常常被复杂的AI写代码工具所困扰。状态管理,作为前端开发的核心难题之一,更是让无数开发者头疼不已。代码维护困难、数据流追踪不易、逻辑混乱等问题层出不穷,严重影响开发效率和项目质量。高效的前端状态管理至关重要,而智能化解决方案的出现,正为我们提供了一条新的出路。前端状态管理的智能模式识别:突破传统方案的局限传统的方案,例如Redux、Vuex等,虽然在一定程度上解决了</div> </li> <li><a href="/article/1889181079055691776.htm" title="React Redux Webpack 项目实战指南" target="_blank">React Redux Webpack 项目实战指南</a> <span class="text-muted">裘羿洲</span> <div>ReactReduxWebpack项目实战指南react-latest-framework项目地址:https://gitcode.com/gh_mirrors/rea/react-redux-webpack本指南将带你深入了解基于https://github.com/hyy1115/react-redux-webpack.git的开源项目,适合React技术栈的学习者和开发者。我们将从项目的基本</div> </li> <li><a href="/article/1889077543382872064.htm" title="前端状态管理全面解析:从 Vuex、Pinia 到 Redux、Recoil" target="_blank">前端状态管理全面解析:从 Vuex、Pinia 到 Redux、Recoil</a> <span class="text-muted">全栈探索者chen</span> <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/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/vuex/1.htm">vuex</a><a class="tag" taget="_blank" href="/search/pinia/1.htm">pinia</a><a class="tag" taget="_blank" href="/search/redux/1.htm">redux</a><a class="tag" taget="_blank" href="/search/recoil/1.htm">recoil</a> <div>前端状态管理全面解析:从Vuex、Pinia到Redux、Recoil前言在现代前端开发中,状态管理(StateManagement)是一个绕不开的话题。随着应用复杂度的提升,组件之间的状态共享变得越来越困难。如何高效、可维护地管理应用状态,是前端开发者必须掌握的技能之一。本文将深入剖析前端状态管理的核心概念,并对比Vuex、Pinia、Redux、Recoil这些主流状态管理库,帮助你选择最适合</div> </li> <li><a href="/article/1888917784746848256.htm" title="next.js + react基础(持续更新)" target="_blank">next.js + react基础(持续更新)</a> <span class="text-muted">wanfeng_09</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>umijshttps://umijs.org/docs/introduce/introducereact:环境搭建、jsx、组件、useState、useEffect、useRef、自定义Hook、智能组件和UI组件redux:RTK、同步状态、异步状态、状态和视图分离Router:基础使用、嵌套路由、路由模式、声明/编程式导航基础扩展:useMemo/useCallback、useReducer</div> </li> <li><a href="/article/1887999391122386944.htm" title="React常用前端框架合集" target="_blank">React常用前端框架合集</a> <span class="text-muted">不知名靓仔</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a> <div>React是Facebook开发的一款用于构建用户界面的JavaScript库。由于其高效、灵活的特性,React成为了目前最流行的前端框架之一。为了帮助开发者更好地利用React构建应用,市场上涌现了许多优秀的辅助工具和框架。本文将详细介绍几个常用的React前端框架及其特点,帮助开发者选择最适合他们项目的工具。一、Redux:状态管理库Redux是一个专为JavaScript应用设计的状态管理</div> </li> <li><a href="/article/1887957408970502144.htm" title="React-redux-dom解决刷新页面后数据丢失的问题" target="_blank">React-redux-dom解决刷新页面后数据丢失的问题</a> <span class="text-muted">YaaLee_</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><a class="tag" taget="_blank" href="/search/redux/1.htm">redux</a><a class="tag" taget="_blank" href="/search/react-redux/1.htm">react-redux</a> <div>为什么要存储react-redux-dom中的数据?当页面刷新之后,redux中的数据会回到初始值,之前存储到redux中的数据也就不复存在了。在reducer文件中:letshopDetailInfo=sessionStorage.getItem('data')?JSON.parse(sessionStorage.getItem('data')):{};letdefaultState={data</div> </li> <li><a href="/article/1887954762125602816.htm" title="react实现页面打开自动全屏展示_Redux 包教包会(一):解救 React 状态危机" target="_blank">react实现页面打开自动全屏展示_Redux 包教包会(一):解救 React 状态危机</a> <span class="text-muted">雯儿ccu</span> <div>前端应用的状态管理日益复杂。随着大前端时代的到来,前端愈来愈注重处理逻辑,而不只是专注UI层面的改进,而以React为代表的前端框架的出现,大大简化了我们编写UI界面的复杂度。虽然React提供了State机制实现状态管理,也有诸如“状态提升”等开发约定,但是这些方案只适用于小型应用,当你的前端应用有多达10个以上页面时,如何让应用状态可控、让协作开发高效成为了亟待解决的问题,而Redux的出现正</div> </li> <li><a href="/article/1887806413284110336.htm" title="由于直接在这里编写一个完整的购物商城代码(涵盖前端和后端)是不现实的,我将为你概述如何使用几种流行的编程语言和技术栈来构建购物商城的关键部分。" target="_blank">由于直接在这里编写一个完整的购物商城代码(涵盖前端和后端)是不现实的,我将为你概述如何使用几种流行的编程语言和技术栈来构建购物商城的关键部分。</a> <span class="text-muted">Josephineds</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>技术栈概述jzsafe.com后端Python+Django/Flask:用于构建RESTfulAPI。Node.js+Express:另一个流行的选择,用于处理API和服务器端逻辑。数据库:如PostgreSQL,MySQL,MongoDB(非关系型)等。前端React/Redux:用于构建单页面应用(SPA)。Vue.js:另一个流行的前端框架。Angular:如果项目规模较大且需要强大的架构</div> </li> <li><a href="/article/1887259659736248320.htm" title="java使用react_基于JVM使用React.js和Spring Boot建立同构的Web应用" target="_blank">java使用react_基于JVM使用React.js和Spring Boot建立同构的Web应用</a> <span class="text-muted">tarv</span> <a class="tag" taget="_blank" href="/search/java%E4%BD%BF%E7%94%A8react/1.htm">java使用react</a> <div>这是一个展示如何使用Java的SpringBoot实现预渲染前端MVC(MVC-frontend)的同构Web应用开源项目:winterbe/spring-react-example·GitHub所谓同构Isomorphic应用是指Javacript在客户端和服务器端同时运行,后端和前端同享相同的代码。传统Web应用是在服务器端产生HTML,然后发往客户端,后来这被客户端MVC改变如Angular</div> </li> <li><a href="/article/1887063092928507904.htm" title="React:TypeScript + react-redux + redux toolkit" target="_blank">React:TypeScript + react-redux + redux toolkit</a> <span class="text-muted">SEKIRO_DJ</span> <a class="tag" taget="_blank" href="/search/TypeScript/1.htm">TypeScript</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/redux/1.htm">redux</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/typescript/1.htm">typescript</a> <div>目录报错reduxtoolkit简易使用笔记报错最初我也只是使用redux+react-redux+redux-thunk,但最近使用创建项目,使用dispatch出现了报错TS2345:Argumentoftype'RootThunkAction'isnotassignabletoparameteroftype'AnyAction'.Property'type'ismissingintype'R</div> </li> <li><a href="/article/1887003817673814016.htm" title="构建动态React作品集:Portfolio-In-React实战指南" target="_blank">构建动态React作品集:Portfolio-In-React实战指南</a> <span class="text-muted">yang lebron</span> <div>本文还有配套的精品资源,点击获取简介:“Portfolio-In-React”是一个利用React技术构建的个人作品集项目,旨在通过JavaScript库创建一个动态和交互式的在线展示平台。项目使用了React组件化、JSX语法、状态管理、生命周期方法、ReactRouter、CSS-in-JS、响应式设计、状态管理库如Redux、测试与调试、代码优化以及CI/CD实践,涵盖了前端开发的多个关键方</div> </li> <li><a href="/article/1887003818172936192.htm" title="React Native项目开发实战:react-native-insider-tempo" target="_blank">React Native项目开发实战:react-native-insider-tempo</a> <span class="text-muted">大思兄的视界</span> <div>本文还有配套的精品资源,点击获取简介:react-native-insider-tempo是一个利用ReactNative框架构建的JavaScript跨平台移动应用项目。它展示了如何使用ReactNative创建可重用组件,使用JavaScript编程,集成状态管理库(如Redux或MobX),与后端API交互,实现样式与布局设计,处理原生模块集成,以及进行热重载、性能优化、测试和版本控制。该项</div> </li> <li><a href="/article/1886865391037247488.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/JavaScript/1.htm">JavaScript</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%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>一、项目搭建1.react项目搭建npxcreate-react-appapp2.安装reduxnpmiredux二、创建store①store/index.jsimport{createStore,combineReducers}from'redux'functionnum(state=0,action){console.log('action',action);switch(action.ty</div> </li> <li><a href="/article/1885879032524894208.htm" title="Web-3.0学习路线" target="_blank">Web-3.0学习路线</a> <span class="text-muted">奶龙牛牛</span> <a class="tag" taget="_blank" href="/search/web3/1.htm">web3</a> <div>方向学习内容✅区块链基础区块链、智能合约、共识机制✅智能合约Solidity/Rust(Ethereum/Solana)✅前端React.js,Next.js,Web3.js,ethers.js✅后端Node.js,Python,Golang(链上数据)✅存储IPFS,Arweave,Filecoin(去中心化存储)✅交互MetaMask,WalletConnect(钱包)如果你是前端开发Reac</div> </li> <li><a href="/article/1885867797028859904.htm" title="jetpack compose 开发架构选择探讨(二)" target="_blank">jetpack compose 开发架构选择探讨(二)</a> <span class="text-muted">iffly-csdn</span> <a class="tag" taget="_blank" href="/search/jetpack/1.htm">jetpack</a><a class="tag" taget="_blank" href="/search/compose/1.htm">compose</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/jetpack/1.htm">jetpack</a><a class="tag" taget="_blank" href="/search/redux/1.htm">redux</a> <div>jetpackcompose开发架构选择探讨(二)本文所有代码均在compose_architecture中,需要的可以自取上篇我们讲解了如何在compose中使用MVVM和MVI架构,并且在最后解决了如何解决多page的通信问题,本篇文章主要来讲解redux架构在compose的实现,不过由于上篇的MVI实现有点不是特别"优雅",没有充分发挥Flow和livedata之间的转换,因此本篇开始之前</div> </li> <li><a href="/article/1885867670776115200.htm" title="jetpack compose 开发架构选择探讨(三)" target="_blank">jetpack compose 开发架构选择探讨(三)</a> <span class="text-muted">iffly-csdn</span> <a class="tag" taget="_blank" href="/search/jetpack/1.htm">jetpack</a><a class="tag" taget="_blank" href="/search/compose/1.htm">compose</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/jetpack-compose/1.htm">jetpack-compose</a><a class="tag" taget="_blank" href="/search/redux/1.htm">redux</a> <div>jetpackcompose开发架构选择探讨(三)jetpackcompose开发架构选择探讨(一)jetpackcompose开发架构选择探讨(二)本文所有代码均在compose_architecture中,需要的可以自取前面两篇文章我们探讨了jetpackcompose如何选用开发架构以及在compose中如何去实现MVVM、MVI以及redux开发架构,当然这里的讨论不是让大家拘泥于某种开发</div> </li> <li><a href="/article/1885844596668297216.htm" title="react + redux 状态管理操作" target="_blank">react + redux 状态管理操作</a> <span class="text-muted">诚诚程程成</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/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>目录1概念2Redux安装3创建子模块并导入4中间件为react注入store5在组件中使用store数据6修改store数据7提交action传参8异步状态操作9redux调试工具1概念Redux是一个全局状态管理的JS库2Redux安装在react中使用redux,官方要求安装两个其他插件:ReduxToolkit和react-reduxReduxToolkit:官方推荐编写redux逻辑的方</div> </li> <li><a href="/article/1885843713452732416.htm" title="React18+Redux+antd 项目实战 JS" target="_blank">React18+Redux+antd 项目实战 JS</a> <span class="text-muted">Alexeigirl</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/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><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a> <div>React18+Redux+antd项目实战jsAntDesign插件官网Axios官网(可配置请求拦截器和响应拦截器)JavaScript官网Echarts官网一、项目前期准备1.创建新项目hotel-managernpxcreate-react-apphotel-manager2.安装依赖//安装路由npmireact-router-domnpmiaixos//安装组件库npmiantdnpm</div> </li> <li><a href="/article/1885838036684566528.htm" title="React【React+Redux应用_Thunk、React+Redux应用_组件、React+Redux应用_DevTools、 为 React 项目添加 Redux、使用数据】(十一)" target="_blank">React【React+Redux应用_Thunk、React+Redux应用_组件、React+Redux应用_DevTools、 为 React 项目添加 Redux、使用数据】(十一)</a> <span class="text-muted">童小纯</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%B3%BB%E5%88%97---%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%B7%B1%E5%8C%96/1.htm">前端系列---从入门到深化</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><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a> <div>文章目录React+Redux应用_ThunkReact+Redux应用_组件React+Redux应用_DevTools为React项目添加Redux使用数据多个ReduxSliceReact+Redux应用_Thunkthunk是一种特定类型的Redux函数,可以包含异步逻辑。1、一个内部thunk函数,它以dispatch和getState作为参数2、外部创建者函数,它创建并返回thunk函</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>